{"record":{"id":"c51c00619dfc409b","repo":"payloadcms/payload","slug":"error-notallowedtoperformaction-c51c00","errorCode":null,"errorMessage":"error:notAllowedToPerformAction","messagePattern":"error:notAllowedToPerformAction","errorType":"exception","errorClass":"Forbidden","httpStatus":403,"severity":"error","filePath":"packages/payload/src/auth/operations/refresh.ts","lineNumber":57,"sourceCode":"      collection: args.collection.config,\n      operation: 'refresh',\n      overrideAccess: false,\n    })\n\n    // /////////////////////////////////////\n    // Refresh\n    // /////////////////////////////////////\n\n    const {\n      collection: { config: collectionConfig },\n      req,\n      req: {\n        payload: { config, secret },\n      },\n    } = args\n\n    if (!args.req.user) {\n      throw new Forbidden(args.req.t)\n    }\n\n    const pathname = new URL(args.req.url!).pathname\n\n    const isGraphQL = pathname === config.routes.graphQL\n\n    let user = await req.payload.db.findOne<AuthenticatedUser>({\n      collection: collectionConfig.slug,\n      req,\n      where: { id: { equals: args.req.user.id } },\n    })\n\n    if (!user) {\n      throw new Forbidden(args.req.t)\n    }\n\n    const sid = args.req.user._sid\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/auth/operations/refresh.ts#L39-L75","documentation":"Thrown at the start of the token-refresh operation when `args.req.user` is falsy. Refresh requires an existing (expiring) JWT to identify and renew; without one there is nothing to refresh. Surfaces as `Forbidden` (HTTP 403) with the i18n message `error:notAllowedToPerformAction`.","triggerScenarios":"A client calls the refresh endpoint (`POST /api/<collection>/refresh-token`) with no token, an already-expired token (middleware rejects → no `req.user`), or a malformed `Authorization` header. Also via Local API `payload.refreshToken({ req })` on an unauthenticated `req`.","commonSituations":"The access token expired and the refresh logic fires after the cookie is already gone; the frontend's refresh call omits credentials (`fetch(..., { credentials: 'omit' })`); a clock-skew between client and server treats the token as expired before refresh runs.","solutions":["Ensure the refresh request carries the `payload-token` cookie / JWT header (`credentials: 'include'`).","Refresh before the access token fully expires (e.g. at ~80% of `tokenExpiration`).","If using the Local API, build `req` from a user: `createLocalReq({ user }, payload)`.","Confirm `config.auth.tokenExpiration` is reasonable and the JWT secret matches the one that signed the token."],"exampleFix":"// before\nfetch('/api/users/refresh-token')\n// after\nfetch('/api/users/refresh-token', { method: 'POST', credentials: 'include' })","handlingStrategy":"validation","validationCode":"// Only refresh when a token is present\nif (!req.user) {\n  // no session to refresh — redirect to login\n  return redirectToLogin()\n}\nawait payload.refreshToken({ collection, req })","typeGuard":"function hasAuthUser(req: PayloadRequest): req is PayloadRequest & { user: AuthUser } {\n  return !!req.user\n}","tryCatchPattern":"try {\n  await payload.refreshToken({ collection, req })\n} catch (e) {\n  if (e instanceof Forbidden) { await redirectToLogin() }\n  else throw e\n}","preventionTips":["Refresh proactively before the access token expires.","Send cookies with `credentials: 'include'`.","Guard refresh logic behind a `req.user` check."],"tags":["auth","refresh","jwt","middleware"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}