{"record":{"id":"15d6ad7aa85391f8","repo":"vxcontrol/pentagi","slug":"token-unauthorized","errorCode":"Token.Unauthorized","errorMessage":"not authorized to access this token","messagePattern":"not authorized to access this token","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"backend/pkg/server/services/api_tokens.go","lineNumber":218,"sourceCode":"\tuid := c.GetUint64(\"uid\")\n\tprms := c.GetStringSlice(\"prm\")\n\ttokenID := c.Param(\"tokenID\")\n\n\tvar token models.APIToken\n\tif err := s.db.Where(\"token_id = ? AND deleted_at IS NULL\", tokenID).First(&token).Error; err != nil {\n\t\tlogger.FromContext(c).WithError(err).Errorf(\"error finding token\")\n\t\tif errors.Is(err, gorm.ErrRecordNotFound) {\n\t\t\tresponse.Error(c, response.ErrTokenNotFound, err)\n\t\t} else {\n\t\t\tresponse.Error(c, response.ErrInternal, err)\n\t\t}\n\t\treturn\n\t}\n\n\thasAdmin := auth.LookupPerm(prms, \"settings.tokens.admin\")\n\tif !hasAdmin && token.UserID != uid {\n\t\tlogger.FromContext(c).Errorf(\"user %d attempted to access token of user %d\", uid, token.UserID)\n\t\tresponse.Error(c, response.ErrTokenUnauthorized, errors.New(\"not authorized to access this token\"))\n\t\treturn\n\t}\n\n\tisExpired := token.CreatedAt.Add(time.Duration(token.TTL) * time.Second).Before(time.Now())\n\tif token.Status == models.TokenStatusActive && isExpired {\n\t\ttoken.Status = models.TokenStatusExpired\n\t}\n\n\tif err := token.Valid(); err != nil {\n\t\tlogger.FromContext(c).WithError(err).Errorf(\"error validating token data\")\n\t\tresponse.Error(c, response.ErrTokenInvalidData, err)\n\t\treturn\n\t}\n\n\tresponse.Success(c, http.StatusOK, token)\n}\n\n// UpdateToken updates name and/or status of a token","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/services/api_tokens.go#L200-L236","documentation":"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.","triggerScenarios":"GET /tokens/{id} where {id} belongs to another user and the caller's permission set lacks settings.tokens.admin.","commonSituations":"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.","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."],"exampleFix":"// before\ncurl /tokens/77  // token 77 owned by user 5, caller is user 9 without admin -> 403\n// after\ncurl /tokens/88  // token owned by caller, or caller has settings.tokens.admin","handlingStrategy":"validation","validationCode":"const myTokens = await api.get('/tokens');\nif (!myTokens.data.tokens.some(t => t.id === tokenId) && !hasPerm('settings.tokens.admin')) {\n  throw new Error('this token belongs to another user');\n}","typeGuard":"function canAccessToken(token, uid, perms) { return perms.includes('settings.tokens.admin') || token.user_id === uid; }","tryCatchPattern":"try { const t = await api.get(`/tokens/${id}`); }\ncatch (e) { if (e.response?.data?.code === 'Token.Unauthorized') showNoAccess(); else throw e; }","preventionTips":["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."],"tags":["authorization","api-tokens","rbac","idor"],"backgroundTag":"insufficient-permission-resource-access","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}