Profiles·Public

@auth0/nextjs-auth0

semver>=2.0.0postconditions32functions21last verified2026-06-24coverage score88%

Postconditions: what we check

  • getAccessToken · access-token-error
    error
    WhenAccess token is expired with no refresh token available, refresh token is revoked by Auth0 (e.g., user password change, admin action), requested scopes are not in the original grant, or no session exists. Also throws FAILED_REFRESH_GRANT under concurrent request load (refresh token rotation race condition).
    ThrowsAccessTokenError with error codes: - MISSING_SESSION / ERR_EXPIRED_ACCESS_TOKEN: no valid session cookie - MISSING_ACCESS_TOKEN / ERR_MISSING_ACCESS_TOKEN: no token in session - MISSING_REFRESH_TOKEN / ERR_MISSING_REFRESH_TOKEN: token expired, no refresh token - EXPIRED_ACCESS_TOKEN / ERR_EXPIRED_ACCESS_TOKEN: refresh attempt failed - INSUFFICIENT_SCOPE / ERR_INSUFFICIENT_SCOPE: requested scopes not available - FAILED_REFRESH_GRANT / ERR_FAILED_REFRESH_GRANT: Auth0 rejected refresh request
    Required handlingCaller MUST wrap in try-catch. When the refresh token expires (default 7-day rotation in Auth0), getAccessToken will throw in production for all authenticated users until they re-authenticate. Unhandled = 500 error. Minimum handling: try { const { accessToken } = await getAccessToken(req, res); } catch (error) { if (error instanceof AccessTokenError) { // Redirect user to re-authenticate res.status(401).json({ message: 'Please sign in again' }); } else { res.status(500).json({ message: 'Internal server error' }); } } Import: import { getAccessToken, AccessTokenError } from '@auth0/nextjs-auth0'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][2][3]
  • handleCallback · callback-handler-error
    error
    WhenOAuth callback fails: invalid or expired state parameter, organization claim mismatch, PKCE code verifier failure, Auth0 returns error in callback URL, or network failure contacting Auth0 token endpoint.
    ThrowsCallbackHandlerError (extends HandlerError) with code ERR_CALLBACK_HANDLER_FAILURE. The .cause property contains the underlying error. The .status property contains the HTTP status code.
    Required handlingCaller MUST wrap in try-catch or provide an onError handler in handleAuth(). Unhandled callback errors crash the auth flow and expose stack traces to users. Minimum handling: export default handleAuth({ async callback(req, res) { try { await handleCallback(req, res, { redirectUri: '/dashboard' }); } catch (error) { res.writeHead(302, { Location: '/error?message=auth_failed' }); res.end(); } } });
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4][5]
  • handleLogin · login-handler-error
    error
    WhenLogin redirect fails due to configuration errors (invalid authorizationParams, bad redirectUri), or any error in the login flow construction.
    ThrowsLoginHandlerError (extends HandlerError) with code ERR_LOGIN_HANDLER_FAILURE. The .cause property contains the underlying error.
    Required handlingCaller MUST wrap in try-catch when using handleLogin() directly (custom handler pattern). Unhandled errors will propagate as 500. Minimum handling: try { await handleLogin(req, res, { returnTo: '/dashboard' }); } catch (error) { res.status(500).json({ error: 'Login failed' }); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6][5]
  • handleLogout · logout-handler-error
    error
    WhenLogout fails due to invalid returnTo URL (not in allowed list), session destruction failure, or network error contacting Auth0 logout endpoint.
    ThrowsLogoutHandlerError (extends HandlerError) with code ERR_LOGOUT_HANDLER_FAILURE.
    Required handlingCaller MUST wrap in try-catch when using handleLogout() directly (custom handler pattern). Unhandled errors will leave the user on a 500 error page with an intact session. Minimum handling: try { await handleLogout(req, res, { returnTo: '/' }); } catch (error) { res.status(500).json({ error: 'Logout failed' }); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7][5]
  • Auth0Client.getSession · auth0-get-session-domain-mismatch
    warning
    WhenAuth0Client is configured with a DomainResolver (Multiple Custom Domains / MCD) and the user's session was created on a different custom domain than the current request domain. Only throws in v4 MCD mode — does not occur in v2/v3 or single-domain configurations.
    ThrowsSessionDomainMismatchError — a named error from @auth0/nextjs-auth0/server. Indicates the session belongs to a different domain (e.g., session from brand-a.com accessed on brand-b.com).
    Required handlingCaller SHOULD catch SessionDomainMismatchError and redirect the user to re-authenticate on the current domain: const session = await auth0.getSession(); // If using MCD, wrap in try-catch: try { const session = await auth0.getSession(); } catch (error) { if (error instanceof SessionDomainMismatchError) { redirect('/auth/login'); } throw error; } Import: import { SessionDomainMismatchError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][2]
  • Auth0Client.getSession · auth0-get-session-no-null-check
    warning
    WhengetSession() returns null when the user is not authenticated (no valid session cookie). Code that destructures the return value without a null guard will throw a TypeError at runtime.
    Returnsnull — when no session exists. This is NOT a thrown error, it is the normal return value for unauthenticated users. The bug is in the caller that destructures null without checking.
    Required handlingAlways null-check before accessing session properties: const session = await auth0.getSession(); if (!session) { return null; // or redirect to login } const { user } = session; // safe — session is not null WRONG (crashes for unauthenticated users): const { user } = await auth0.getSession(); // TypeError if null
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][2]
  • Auth0Client.getAccessToken · auth0-v4-access-token-missing-session
    error
    WhenCalled with no active user session (no valid session cookie, or session has expired). In the v4 App Router pattern this is the most common failure mode: server actions and route handlers called by unauthenticated users or after session expiry will throw without a try-catch.
    ThrowsAccessTokenError with code AccessTokenErrorCode.MISSING_SESSION ("missing_session"). Import AccessTokenError from '@auth0/nextjs-auth0/server'.
    Required handlingCaller MUST wrap in try-catch and convert to a 401 response: try { const { token } = await auth0.getAccessToken(); return token; } catch (error) { if (error instanceof AccessTokenError) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } throw error; } Import: import { AccessTokenError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][2]
  • Auth0Client.getAccessToken · auth0-v4-access-token-refresh-failed
    error
    WhenThe access token is expired and the refresh token is also expired, revoked (by user password change, admin action, or token rotation race condition), or the refresh grant is rejected by Auth0. Refresh tokens expire after a configurable interval (default 7 days rolling in Auth0 Free/Pro tiers).
    ThrowsAccessTokenError with code AccessTokenErrorCode.FAILED_TO_REFRESH_TOKEN ("failed_to_refresh_token") or AccessTokenErrorCode.MISSING_REFRESH_TOKEN ("missing_refresh_token"). The .cause property contains the underlying OAuth2Error from Auth0.
    Required handlingMust catch AccessTokenError and redirect to re-authentication: try { const { token } = await auth0.getAccessToken(); } catch (error) { if (error instanceof AccessTokenError) { redirect('/auth/login'); // force re-auth } throw error; }
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[8][2]
  • Auth0Client.getAccessToken · auth0-v4-access-token-mfa-required
    warning
    WhenAuth0 returns mfa_required during token refresh when the API audience requires step-up MFA authentication. The user has a valid session but must complete an MFA challenge before receiving the token.
    ThrowsMfaRequiredError — contains an encrypted mfa_token property (string) that must be passed to auth0.mfa.getAuthenticators() to start the MFA flow. Also contains mfa_requirements listing available challenge types.
    Required handlingMust catch MfaRequiredError separately and initiate the MFA challenge: try { const { token } = await auth0.getAccessToken({ audience }); } catch (error) { if (error instanceof MfaRequiredError) { // Store mfa_token and redirect to MFA challenge page redirect(`/mfa?token=${error.mfa_token}`); } throw error; } Import: import { MfaRequiredError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[8][2]
  • Auth0Client.getAccessTokenForConnection · auth0-connection-token-missing-session
    error
    WhenNo active user session exists when calling getAccessTokenForConnection(). A valid session is required to exchange for a connection token.
    ThrowsAccessTokenForConnectionError with code AccessTokenForConnectionErrorCode.MISSING_SESSION ("missing_session").
    Required handlingMust wrap in try-catch and return 401 for unauthenticated callers: try { const { token } = await auth0.getAccessTokenForConnection({ connection: 'github' }); } catch (error) { if (error instanceof AccessTokenForConnectionError) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } throw error; } Import: import { AccessTokenForConnectionError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][2]
  • Auth0Client.getAccessTokenForConnection · auth0-connection-token-exchange-failed
    error
    WhenAuth0 rejects the connection token exchange. Occurs when the connection is not configured for Offline Access in Auth0, the refresh token was revoked, or the user revoked the third-party app's permissions on the external provider.
    ThrowsAccessTokenForConnectionError with code AccessTokenForConnectionErrorCode.FAILED_TO_EXCHANGE ("failed_to_exchange_refresh_token"). The .cause property contains the underlying OAuth2Error.
    Required handlingMust catch and prompt user to re-authorize the connection: try { const { token } = await auth0.getAccessTokenForConnection({ connection: 'github' }); } catch (error) { if (error instanceof AccessTokenForConnectionError && error.code === 'failed_to_exchange_refresh_token') { // Prompt user to reconnect their GitHub account redirect('/settings/connections'); } throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][2]
  • Auth0Client.updateSession · auth0-update-session-unauthenticated
    error
    WhenCalled without an active user session (user is not logged in, session has expired, or the session cookie is missing). Unlike getSession() which returns null, updateSession() throws when unauthenticated.
    ThrowsError("The user is not authenticated.") — a plain Error, not an SdkError subclass. Also throws Error("The session data is missing.") if the session argument is undefined or null.
    Required handlingMust wrap in try-catch or verify session existence first: const session = await auth0.getSession(); if (!session) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } // Now safe to update await auth0.updateSession({ ...session, user: { ...session.user, role: 'admin' } });
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][2]
  • Auth0Client.updateSession · auth0-update-session-server-component-no-persist
    warning
    WhenupdateSession() is called from a React Server Component (not a Server Action or Route Handler). Server Components cannot set cookies, so the session update is silently discarded even though no error is thrown.
    ReturnsPromise<void> — resolves without error but the updated session is NOT persisted. The next request will still see the old session data.
    Required handlingMove updateSession() calls to Server Actions or Route Handlers where cookies can be set. Do not call from Server Components for data that must persist: // WRONG — in a Server Component: await auth0.updateSession(updatedSession); // silently ignored // CORRECT — in a Server Action: 'use server'; async function updateUserRole(role: string) { const session = await auth0.getSession(); await auth0.updateSession({ ...session!, user: { ...session!.user, role } }); }
    costlowin prodsilent failureusers seelost datavisibilitysilent
    Sources[8][2]
  • Auth0Client.customTokenExchange · auth0-cte-missing-subject-token
    error
    WhenThe subjectToken parameter is empty, null, or undefined. This validation error is thrown before the network request is made.
    ThrowsCustomTokenExchangeError with code CustomTokenExchangeErrorCode.MISSING_SUBJECT_TOKEN ("missing_subject_token"). Thrown synchronously during input validation.
    Required handlingValidate the subject token before calling customTokenExchange(): if (!subjectToken) { return NextResponse.json({ error: 'Missing token' }, { status: 400 }); } try { const result = await auth0.customTokenExchange({ subjectToken, subjectTokenType }); } catch (error) { if (error instanceof CustomTokenExchangeError) { return NextResponse.json({ error: error.message }, { status: 400 }); } throw error; } Import: import { CustomTokenExchangeError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9][2]
  • Auth0Client.customTokenExchange · auth0-cte-exchange-failed
    error
    WhenAuth0 rejects the token exchange. Common causes: subjectTokenType not registered in Auth0 tenant settings, the subject token has expired, invalid token signature, or the client is not authorized for Custom Token Exchange.
    ThrowsCustomTokenExchangeError with code CustomTokenExchangeErrorCode.EXCHANGE_FAILED ("exchange_failed"). The .cause property contains the underlying OAuth2Error with Auth0's error description.
    Required handlingMust wrap in try-catch and handle exchange failures: try { const result = await auth0.customTokenExchange({ subjectToken, subjectTokenType }); return result; } catch (error) { if (error instanceof CustomTokenExchangeError) { return NextResponse.json({ error: 'Token exchange failed' }, { status: 401 }); } throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9][2]
  • Auth0Client.mfa.getAuthenticators · auth0-mfa-get-authenticators-token-invalid
    error
    WhenThe mfaToken has expired (default TTL: 5 minutes, configurable via mfaTokenTtl option) or was tampered with. The token is an encrypted JWE — modification or re-encryption with a different secret causes MfaTokenInvalidError.
    ThrowsMfaTokenExpiredError when the token's TTL has passed. MfaTokenInvalidError when the token is malformed, tampered, or encrypted with a different secret key.
    Required handlingMust catch both token errors and restart the MFA flow: try { const authenticators = await auth0.mfa.getAuthenticators({ mfaToken }); } catch (error) { if (error instanceof MfaTokenExpiredError || error instanceof MfaTokenInvalidError) { // mfa_token is lost — user must restart auth flow return NextResponse.json({ error: 'MFA session expired, please try again' }, { status: 401 }); } throw error; } Import: import { MfaTokenExpiredError, MfaTokenInvalidError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[10][2]
  • Auth0Client.mfa.getAuthenticators · auth0-mfa-get-authenticators-api-error
    error
    WhenThe Auth0 MFA API request fails. Common causes: Auth0-side token rejection (invalid_token error), network failure reaching the Auth0 API, or the tenant's MFA configuration is missing or misconfigured.
    ThrowsMfaGetAuthenticatorsError — the .cause property contains the Auth0 API error response with error and error_description fields (snake_case).
    Required handlingMust wrap in try-catch and handle API failures gracefully: try { const authenticators = await auth0.mfa.getAuthenticators({ mfaToken }); } catch (error) { if (error instanceof MfaGetAuthenticatorsError) { return Response.json(error, { status: 400 }); } throw error; } Import: import { MfaGetAuthenticatorsError } from the mfa-errors module
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[10][2]
  • Auth0Client.mfa.challenge · auth0-mfa-challenge-invalid-authenticator
    error
    WhenThe specified authenticatorId does not exist in Auth0 or is not active. The authenticator may have been removed between listing and challenging, or the wrong property was used to extract the ID from the Authenticator object.
    ThrowsMfaChallengeError with cause.error = 'invalid_authenticator_id'. The error is returned from the Auth0 MFA API.
    Required handlingMust catch MfaChallengeError and offer fallback options to the user: try { const challenge = await auth0.mfa.challenge({ mfaToken, challengeType, authenticatorId }); } catch (error) { if (error instanceof MfaChallengeError) { return Response.json({ error: 'Authenticator not found' }, { status: 400 }); } throw error; }
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[10][2]
  • Auth0Client.mfa.challenge · auth0-mfa-challenge-no-factors
    error
    WhenNo enrolled MFA authenticators match the mfa_requirements from the MfaRequiredError (user has no active MFA factors of the required type). This is an SDK-generated error — no Auth0 API call is attempted.
    ThrowsMfaNoAvailableFactorsError — SDK-only error, no Auth0 round-trip. The user must enroll a new authenticator via mfa.enroll() before proceeding.
    Required handlingMust catch and redirect the user to MFA enrollment: try { const challenge = await auth0.mfa.challenge({ mfaToken, challengeType: 'otp' }); } catch (error) { if (error instanceof MfaNoAvailableFactorsError) { redirect('/mfa/enroll'); // guide user to enroll a new factor } throw error; }
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[10][2]
  • Auth0Client.mfa.verify · auth0-mfa-verify-invalid-grant
    error
    WhenThe submitted OTP/OOB code is incorrect, has already been used, or has expired. This is the most common MFA verification failure — users mistype codes, codes expire (TOTP is time-based), or SMS codes are slow to arrive.
    ThrowsMfaVerifyError with cause.error = 'invalid_grant'. The mfaToken remains valid until its own TTL expires, allowing the user to retry with a new code.
    Required handlingMust catch MfaVerifyError and return a user-friendly "invalid code" message: try { const tokens = await auth0.mfa.verify({ mfaToken, otp: userOtp }); return tokens; } catch (error) { if (error instanceof MfaVerifyError && error.cause?.error === 'invalid_grant') { return Response.json({ error: 'Invalid or expired code, please try again' }, { status: 400 }); } throw error; }
    costlowin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[10][2]
  • Auth0Client.mfa.enroll · auth0-mfa-enroll-unsupported-type
    error
    WhenThe Auth0 tenant does not have the requested authenticator type enabled (e.g., enrolling OTP when only email MFA is enabled in tenant settings). Tenant MFA configuration must match the enrollment options presented to users.
    ThrowsMfaEnrollmentError with cause.error = 'unsupported_challenge_type'. The application must verify which authenticator types are enabled in the Auth0 tenant before presenting enrollment options.
    Required handlingMust catch MfaEnrollmentError and inform the user which types are supported: try { const enrollment = await auth0.mfa.enroll({ mfaToken, authenticatorTypes: ['otp'] }); return enrollment; } catch (error) { if (error instanceof MfaEnrollmentError) { return Response.json({ error: 'Authenticator type not supported' }, { status: 400 }); } throw error; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[10][2]
  • Auth0Client.getTokenByBackchannelAuth · auth0-ciba-not-supported
    error
    WhenThe Auth0 tenant does not have CIBA (Client-Initiated Backchannel Authentication) enabled. CIBA must be explicitly enabled in the Auth0 dashboard. The error is thrown during the OIDC discovery phase — before any user interaction occurs.
    ThrowsBackchannelAuthenticationNotSupportedError — thrown immediately when CIBA is not present in the Auth0 discovery document's backchannel_authentication_endpoint.
    Required handlingMust catch to avoid crashes on tenants without CIBA enabled: try { const tokens = await auth0.getTokenByBackchannelAuth({ bindingMessage, loginHint }); } catch (error) { if (error instanceof BackchannelAuthenticationNotSupportedError) { return NextResponse.json({ error: 'CIBA not configured' }, { status: 501 }); } throw error; } Import: import { BackchannelAuthenticationNotSupportedError } from '@auth0/nextjs-auth0/server'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9][11]
  • Auth0Client.getTokenByBackchannelAuth · auth0-ciba-denied-or-expired
    error
    WhenThe user denies the push notification, fails to respond within the request expiry window (default 300 seconds / 5 minutes, configurable via requestedExpiry), or Auth0 returns an error during the polling phase (e.g., access_denied, expired_token, slow_down).
    ThrowsBackchannelAuthenticationError — the .cause property contains the underlying OAuth2Error with the specific denial/timeout reason (access_denied, expired_token).
    Required handlingMust catch and notify the consumption device that the action was cancelled: try { const tokens = await auth0.getTokenByBackchannelAuth({ bindingMessage, loginHint }); return tokens; } catch (error) { if (error instanceof BackchannelAuthenticationError) { // Notify user on consumption device that auth was denied/timed out return NextResponse.json({ error: 'Authentication was denied or timed out' }, { status: 401 }); } throw error; }
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[9][11]
  • Auth0Client.passkey.register · auth0-passkey-register-not-enabled
    error
    WhenPasskey grants are not enabled on the Auth0 application, the tenant has no passkey-capable connection configured, or the request fails the discovery / configuration check. Auth0 returns an error body which is rewrapped into PasskeyRegisterError. This is the very first call in the signup flow — if it throws, the entire signup screen breaks for every user.
    ThrowsPasskeyRegisterError with .error / .error_description from the Auth0 API response (e.g. "unauthorized_client", "invalid_request"). Catch-all: when the network call itself fails (DNS, timeout, 5xx), the wrapper throws PasskeyRegisterError("unexpected_error", ...).
    Required handlingMust wrap in try-catch — there is no fallback if the challenge call fails. The browser cannot proceed to navigator.credentials.create() without authnParamsPublicKey. Surface a user-actionable error so users can fall back to a different signup method. try { const challenge = await auth0.passkey.register({ email, name }); return NextResponse.json(challenge); } catch (error) { if (error instanceof PasskeyRegisterError) { return NextResponse.json( { error: error.error_description, code: error.code }, { status: 400 } ); } throw error; } Import: import { PasskeyRegisterError } from '@auth0/nextjs-auth0/errors'
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
  • Auth0Client.passkey.challenge · auth0-passkey-challenge-no-credential
    error
    WhenThe user has not registered any passkey on their account, passkeys are disabled on the connection, or the Auth0 API returns an error during the discovery / configuration phase. Unhandled, the login UI hangs waiting for authnParamsPublicKey that never arrives.
    ThrowsPasskeyChallengeError with .error / .error_description from the Auth0 API response. Wrapper also throws PasskeyChallengeError("unexpected_error", ...) when the underlying fetch fails (network, timeout, 5xx).
    Required handlingMust wrap in try-catch and surface a typed error so the login UI can fall back to password login or magic link. A bare unhandled rejection here renders the entire passkey-login button useless without telling the user why. try { const challenge = await auth0.passkey.challenge(); return NextResponse.json(challenge); } catch (error) { if (error instanceof PasskeyChallengeError) { return NextResponse.json( { error: 'Passkey not available, please use password', code: error.code }, { status: 400 } ); } throw error; } Import: import { PasskeyChallengeError } from '@auth0/nextjs-auth0/errors'
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
  • Auth0Client.passkey.getToken · auth0-passkey-gettoken-mfa-required
    error
    WhenThe Auth0 tenant requires multi-factor authentication for this user after a successful passkey assertion (step-up MFA). v4.23.0 surfaces this as MfaRequiredError with an encrypted mfa_token that must be passed to auth0.mfa.challenge() / auth0.mfa.verify(). Callers upgrading from v4.22 who only catch PasskeyGetTokenError now have an uncaught MfaRequiredError that crashes the auth route.
    ThrowsMfaRequiredError (added v4.23.0 BREAKING) with .mfaToken (encrypted), .mfaRequirements, and .cause (OAuth2Error). The mfa_token must be passed as-is into the MFA challenge / verify methods — the SDK encrypts and rotates it internally.
    Required handlingUpgrading to v4.23+: must catch MfaRequiredError separately from PasskeyGetTokenError. Redirect to MFA challenge flow rather than treating as a generic auth failure. try { await auth0.passkey.getToken({ authSession, authResponse }); return new Response(null, { status: 204 }); } catch (error) { if (error instanceof MfaRequiredError) { // Persist encrypted mfa_token, redirect to MFA challenge UI return NextResponse.redirect(`/mfa?token=${error.mfaToken}`); } if (error instanceof PasskeyGetTokenError) { return NextResponse.json({ error: error.error_description }, { status: 401 }); } throw error; } Import: import { MfaRequiredError, PasskeyGetTokenError } from '@auth0/nextjs-auth0/errors'
    costhighin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
  • Auth0Client.passkey.getToken · auth0-passkey-gettoken-invalid-assertion
    error
    WhenThe WebAuthn assertion sent by the browser was rejected by Auth0 — invalid or expired authSession (the challenge has a short TTL, typically 5 minutes), credential signature verification failed, the passkey is not recognized for this user, or the id_token returned has a mismatched issuer/audience. All of these become PasskeyGetTokenError with distinct .code values (invalid_grant, invalid_issuer, invalid_audience, missing_id_token).
    ThrowsPasskeyGetTokenError with .error_description detailing the rejection. Specific known .code values: - "invalid_issuer": ID token issuer mismatch (AUTH0_DOMAIN config drift) - "invalid_audience": ID token audience mismatch (AUTH0_CLIENT_ID config drift) - "missing_id_token": openid scope was not requested - Auth0 OAuth error.error pass-through for credential rejection cases
    Required handlingMust catch to provide actionable feedback — config errors (invalid_issuer / invalid_audience) signal env var drift between deploys and need ops alerts, not user-facing retry. Credential rejection means the user should re-authenticate via a different method (the passkey may have been deleted on the device or revoked). try { await auth0.passkey.getToken({ authSession, authResponse }); } catch (error) { if (error instanceof PasskeyGetTokenError) { if (error.code === 'invalid_issuer' || error.code === 'invalid_audience') { console.error('Auth0 config drift', error); return NextResponse.json({ error: 'Server misconfiguration' }, { status: 500 }); } return NextResponse.json({ error: 'Passkey rejected, please retry' }, { status: 401 }); } throw error; }
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[9][12]
  • Auth0Client.passkey.enrollmentChallenge · auth0-passkey-enrollment-challenge-missing-scope
    error
    WhenThe user does not have an active session, the access token lacks the create:me:authentication_methods scope, or passkeys are not enabled on the Auth0 tenant. The MyAccount API returns an RFC 7807 problem detail which is rewrapped into PasskeyEnrollmentChallengeError.
    ThrowsPasskeyEnrollmentChallengeError with .error / .error_description and .cause containing the RFC 7807 problem detail. .code values include "insufficient_scope", "unauthorized", "passkey_not_enabled".
    Required handlingMust catch to differentiate "user must re-authenticate with broader scope" from "feature not enabled by admin". These need different UX (re-login vs contact admin): try { const challenge = await auth0.passkey.enrollmentChallenge(); return NextResponse.json(challenge); } catch (error) { if (error instanceof PasskeyEnrollmentChallengeError) { if (error.code === 'insufficient_scope' || error.code === 'unauthorized') { return NextResponse.json({ error: 'Re-authenticate to enroll passkey' }, { status: 401 }); } return NextResponse.json({ error: 'Passkey enrollment unavailable' }, { status: 400 }); } throw error; } Import: import { PasskeyEnrollmentChallengeError } from '@auth0/nextjs-auth0/errors'
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
  • Auth0Client.passkey.enrollmentVerify · auth0-passkey-enrollment-verify-duplicate-or-rejected
    error
    WhenThe authSession from enrollmentChallenge has expired (default 5min TTL), the WebAuthn attestation signature does not validate against the Auth0 RP-ID, or the credential is a duplicate (already enrolled on this account). The MyAccount API returns an RFC 7807 problem detail which is rewrapped into PasskeyEnrollmentVerifyError.
    ThrowsPasskeyEnrollmentVerifyError with .error / .error_description. Common .code values: "invalid_grant" (expired session), "duplicate_credential", "attestation_rejected".
    Required handlingMust catch — silent enrollment failure is the worst-case here. Users believe they have set up a passkey but the next login fails. Return a typed error so the UI can prompt to retry or report duplicates clearly: try { const passkey = await auth0.passkey.enrollmentVerify({ authenticationMethodId, authSession, authResponse, }); return NextResponse.json(passkey); } catch (error) { if (error instanceof PasskeyEnrollmentVerifyError) { if (error.code === 'duplicate_credential') { return NextResponse.json({ error: 'Passkey already enrolled' }, { status: 409 }); } return NextResponse.json({ error: 'Enrollment failed, please retry' }, { status: 400 }); } throw error; } Import: import { PasskeyEnrollmentVerifyError } from '@auth0/nextjs-auth0/errors'
    costhighin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[12][18]
  • Auth0Client.passwordless.start · auth0-passwordless-start-rate-limit-or-disabled
    error
    WhenThe Auth0 passwordless connection (email or sms) is not enabled on the application, the email/phoneNumber is missing or malformed, Auth0's send rate limit for this identifier has been exceeded (default 5 sends per hour per identifier), or the underlying SMS provider rejected the number.
    ThrowsPasswordlessStartError with .error / .error_description from the Auth0 API response. Specific .error values include: - "bad.connection" / "connection_disabled": connection not enabled - "bad.email" / "bad.phone_number": invalid identifier - "too_many_requests" / "rate_limit_exceeded": send rate limit hit - "unexpected_error": network failure or 5xx
    Required handlingMust catch — silent failure here is the #1 passwordless bug. The user clicks "Send" expecting a code; if start() throws unhandled, the form posts but no code arrives. Distinguish rate-limit from validation errors so the UI can show "Please wait 1 minute" vs "Please check your email address": try { await auth0.passwordless.start({ connection: 'email', email, send: 'code' }); return NextResponse.json({ sent: true }); } catch (error) { if (error instanceof PasswordlessStartError) { if (error.code === 'too_many_requests' || error.error === 'rate_limit_exceeded') { return NextResponse.json({ error: 'Please wait before trying again' }, { status: 429 }); } return NextResponse.json({ error: 'Could not send code, check your email' }, { status: 400 }); } throw error; } Import: import { PasswordlessStartError } from '@auth0/nextjs-auth0/errors'
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
  • Auth0Client.passwordless.verify · auth0-passwordless-verify-mfa-required
    error
    WhenThe Auth0 tenant requires multi-factor authentication for this user after a successful passwordless OTP verification. v4.23.0 surfaces this as MfaRequiredError (BREAKING) with an encrypted mfa_token to pass to the MFA challenge/verify flow. Callers upgrading from v4.21/4.22 who only catch PasswordlessVerifyError now have an uncaught MfaRequiredError that crashes the verify route after the user entered the correct OTP.
    ThrowsMfaRequiredError (added v4.23.0 BREAKING) with .mfaToken (encrypted), .mfaRequirements, and .cause (OAuth2Error). The mfa_token must be passed into the MFA challenge / verify methods.
    Required handlingUpgrading to v4.23+: must catch MfaRequiredError separately. Redirect to MFA challenge UI rather than showing a generic "Login failed" error (which would make users re-request a passwordless code they already used successfully): try { await auth0.passwordless.verify({ connection: 'email', email, verificationCode }); return NextResponse.redirect('/dashboard'); } catch (error) { if (error instanceof MfaRequiredError) { return NextResponse.redirect(`/mfa?token=${error.mfaToken}`); } if (error instanceof PasswordlessVerifyError) { return NextResponse.json({ error: error.error_description }, { status: 401 }); } throw error; } Import: import { MfaRequiredError, PasswordlessVerifyError } from '@auth0/nextjs-auth0/errors'
    costhighin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
  • Auth0Client.passwordless.verify · auth0-passwordless-verify-invalid-otp
    error
    WhenThe OTP code entered by the user is invalid, expired (default 3min TTL on Auth0), already-used, or the connection/identifier combination does not match the original start() call. Also includes the openid-scope misconfiguration cases (missing_id_token, invalid_issuer, invalid_audience) that surface as typed PasswordlessVerifyError.
    ThrowsPasswordlessVerifyError with .error / .error_description. Known .code values: - Auth0 OAuth error pass-through for "invalid_grant" (wrong/expired OTP) - "missing_id_token": openid scope was not requested - "invalid_issuer": ID token issuer mismatch (AUTH0_DOMAIN config drift) - "invalid_audience": ID token audience mismatch (AUTH0_CLIENT_ID config drift) - "discovery_error": OIDC discovery endpoint failed - "unexpected_error": network failure or 5xx
    Required handlingMust catch — without it, an unhandled rejection on a typo in the OTP field is a 500 error to the user. Show a typed message so the user can re-enter the code or request a new one: try { await auth0.passwordless.verify({ connection: 'email', email, verificationCode }); } catch (error) { if (error instanceof PasswordlessVerifyError) { if (error.code === 'invalid_issuer' || error.code === 'invalid_audience') { console.error('Auth0 config drift', error); return NextResponse.json({ error: 'Server misconfiguration' }, { status: 500 }); } return NextResponse.json({ error: 'Invalid or expired code' }, { status: 401 }); } throw error; }
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[9][20]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation
Source code
Changelog & releases
Issues & pull requests

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

Sources — @auth0/nextjs-auth0

Official Documentation

Primary API Reference

Examples & Error Handling

Quickstart

Version Information

  • Package: @auth0/nextjs-auth0
  • Contract semver range: >=2.0.0 <4.0.0
  • v2.x and v3.x share the same standalone function API
  • v4.x (Auth0Client instance pattern) requires a separate contract

Error Types

AccessTokenError (getAccessToken)

import { AccessTokenError, AccessTokenErrorCode } from '@auth0/nextjs-auth0';

// Error codes:
AccessTokenErrorCode.MISSING_SESSION          // 'ERR_EXPIRED_ACCESS_TOKEN'
AccessTokenErrorCode.MISSING_ACCESS_TOKEN     // 'ERR_MISSING_ACCESS_TOKEN'
AccessTokenErrorCode.MISSING_REFRESH_TOKEN    // 'ERR_MISSING_REFRESH_TOKEN'
AccessTokenErrorCode.EXPIRED_ACCESS_TOKEN     // 'ERR_EXPIRED_ACCESS_TOKEN'
AccessTokenErrorCode.INSUFFICIENT_SCOPE       // 'ERR_INSUFFICIENT_SCOPE'
AccessTokenErrorCode.FAILED_REFRESH_GRANT     // 'ERR_FAILED_REFRESH_GRANT'

Handler Errors

import { HandlerError, CallbackHandlerError, LoginHandlerError, LogoutHandlerError } from '@auth0/nextjs-auth0';

Real-World Evidence

  • Local: test-repos/nextjs/examples/auth0/pages/api/protected-api.tsgetSession called without try-catch (official example missing error handling)
  • npm downloads: ~3.8M weekly (major auth provider for Next.js SaaS)
  • Evidence quality: partial (local example confirmed; broader corpus TBD)
Need a different package?
Request a profile