{"record":{"id":"b94b41bb3172f7ce","repo":"nextauthjs/next-auth","slug":"accessdenied","errorCode":null,"errorMessage":"AccessDenied","messagePattern":"AccessDenied","errorType":"exception","errorClass":"AccessDenied","httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/actions/callback/index.ts","lineNumber":549,"sourceCode":"  } catch (e) {\n    if (e instanceof AuthError) throw e\n    const error = new CallbackRouteError(e as Error, { provider: provider.id })\n    logger.debug(\"callback route error details\", { method, query, body })\n    throw error\n  }\n}\n\nasync function handleAuthorized(\n  params: Parameters<InternalOptions[\"callbacks\"][\"signIn\"]>[0],\n  config: InternalOptions\n): Promise<string | undefined> {\n  let authorized\n  const { signIn, redirect } = config.callbacks\n  try {\n    authorized = await signIn(params)\n  } catch (e) {\n    if (e instanceof AuthError) throw e\n    throw new AccessDenied(e as Error)\n  }\n  if (!authorized) throw new AccessDenied(\"AccessDenied\")\n  if (typeof authorized !== \"string\") return\n  return await redirect({ url: authorized, baseUrl: config.url.origin })\n}\n","sourceCodeStart":531,"sourceCodeEnd":555,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/actions/callback/index.ts#L531-L555","documentation":"AccessDenied with message 'AccessDenied' is thrown by handleAuthorized when the `signIn` callback in the auth config resolves to a falsy value (false, null, undefined, 0, ''). The signIn callback is the application's authorization gate; returning falsy tells Auth.js the user is not allowed to proceed, and the framework converts that into an AccessDenied error that propagates to the client as an access-denied result.","triggerScenarios":"Any sign-in flow (oauth, credentials, email, webauthn) where the configured `callbacks.signIn` returns false or another falsy value — e.g. an allowlist check failing, a banned user, or an accidentally missing return statement in the callback.","commonSituations":"Domain allowlist (only @company.com emails) rejecting a personal Gmail account; signIn callback with early-return branches that fall through without a return; conditional logic that returns false in production but passed in dev; users testing with uninvited accounts.","solutions":["Review the `callbacks.signIn` implementation and ensure intended paths return true (or a redirect URL)","Log the user/profile inside signIn to see which condition evaluates falsy in production","If the rejection is intended, handle the AccessDenied / accessdenied error or ?error=AccessDenied redirect on the client instead of treating it as a bug","Update allowlists or rules so legitimate users pass the gate"],"exampleFix":"// before\ncallbacks: {\n  signIn: async ({ user }) => {\n    if (user.email?.endsWith(\"@corp.com\")) return true\n    // falls through -> undefined -> AccessDenied\n  }\n}\n// after\ncallbacks: {\n  signIn: async ({ user }) => {\n    if (user.email?.endsWith(\"@corp.com\")) return true\n    return false // explicit, and handle the denial client-side\n  }\n}","handlingStrategy":"validation","validationCode":"// config-time check: every branch of signIn must return\nconst signInCb = callbacks.signIn\nif (signInCb) {\n  const r = await signInCb({ user: mockUser, account: mockAccount } as any)\n  console.assert(r !== undefined, \"signIn callback must return true/false/url\")\n}","typeGuard":"function isAllowed(r: unknown): r is true | string {\n  return r === true || typeof r === \"string\"\n}","tryCatchPattern":"try {\n  await signIn(providerId)\n} catch (e) {\n  if (e instanceof AccessDenied) {\n    // user was rejected by your signIn callback\n    redirect(\"/auth/denied\")\n  }\n}","preventionTips":["Ensure every code path in callbacks.signIn returns a value (true/false/URL)","Test signIn callback against both allowed and denied users","Check ?error=AccessDenied redirects in the client UI","Log the user profile inside signIn when diagnosing production denials"],"tags":["authorization","access-denied","callbacks"],"backgroundTag":"signin-callback-denied","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}