vxcontrol/pentagi · warning
Token.Unauthorized
Token.Unauthorized
Error message
not authorized to access this token
What it means
GetToken performs an authorization check after loading the token: unless the caller holds the 'settings.tokens.admin' permission, a user may only read their own tokens (token.UserID == uid). Otherwise it returns Token.Unauthorized with 'not authorized to access this token'. This prevents IDOR-style access to other users' tokens by ID.
Source
Thrown at backend/pkg/server/services/api_tokens.go:218
uid := c.GetUint64("uid")
prms := c.GetStringSlice("prm")
tokenID := c.Param("tokenID")
var token models.APIToken
if err := s.db.Where("token_id = ? AND deleted_at IS NULL", tokenID).First(&token).Error; err != nil {
logger.FromContext(c).WithError(err).Errorf("error finding token")
if errors.Is(err, gorm.ErrRecordNotFound) {
response.Error(c, response.ErrTokenNotFound, err)
} else {
response.Error(c, response.ErrInternal, err)
}
return
}
hasAdmin := auth.LookupPerm(prms, "settings.tokens.admin")
if !hasAdmin && token.UserID != uid {
logger.FromContext(c).Errorf("user %d attempted to access token of user %d", uid, token.UserID)
response.Error(c, response.ErrTokenUnauthorized, errors.New("not authorized to access this token"))
return
}
isExpired := token.CreatedAt.Add(time.Duration(token.TTL) * time.Second).Before(time.Now())
if token.Status == models.TokenStatusActive && isExpired {
token.Status = models.TokenStatusExpired
}
if err := token.Valid(); err != nil {
logger.FromContext(c).WithError(err).Errorf("error validating token data")
response.Error(c, response.ErrTokenInvalidData, err)
return
}
response.Success(c, http.StatusOK, token)
}
// UpdateToken updates name and/or status of a tokenView on GitHub (pinned to ea665308ba)
Solutions
- Log in as the user who owns the token, or have the owner fetch it.
- Grant the caller the settings.tokens.admin permission if cross-user token administration is intended.
- Verify you are using the correct token ID for the current authenticated user.
- If admin access is required, use an account whose role actually includes the settings.tokens.admin permission.
Example fix
// before curl /tokens/77 // token 77 owned by user 5, caller is user 9 without admin -> 403 // after curl /tokens/88 // token owned by caller, or caller has settings.tokens.admin
Defensive patterns
Strategy: validation
Validate before calling
const myTokens = await api.get('/tokens');
if (!myTokens.data.tokens.some(t => t.id === tokenId) && !hasPerm('settings.tokens.admin')) {
throw new Error('this token belongs to another user');
} Type guard
function canAccessToken(token, uid, perms) { return perms.includes('settings.tokens.admin') || token.user_id === uid; } Try / catch
try { const t = await api.get(`/tokens/${id}`); }
catch (e) { if (e.response?.data?.code === 'Token.Unauthorized') showNoAccess(); else throw e; } Prevention
- Only iterate token IDs returned from your own /tokens list.
- Request the settings.tokens.admin permission when cross-user visibility is required.
- Don't hardcode token IDs from other environments/accounts.
- Treat 403 Token.Unauthorized as 'wrong owner', not a bug to retry.
When it happens
Trigger: GET /tokens/{id} where {id} belongs to another user and the caller's permission set lacks settings.tokens.admin.
Common situations: Script iterating token IDs copied from another user/admin session; token ID cached from a previous account; team member trying to inspect a colleague's token without admin grants; role change revoked the admin permission but old scripts still run.
Related errors
- permission 'resources.view' required to use resource IDs
- resource %d not accessible
- user has been blocked
- Token.CreationDisabled
- Token.InvalidRequest
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/15d6ad7aa85391f8.
Report an issue: GitHub.