nextauthjs/next-auth · error · InvalidCheck
WebAuthn challenge was missing
Error message
WebAuthn challenge was missing
What it means
The WebAuthn check's `use` throws InvalidCheck("WebAuthn challenge was missing") when decoding the webauthnChallenge cookie at the callback/verification step yields no payload. The challenge is stored in a cookie when the WebAuthn flow starts and must be present to verify the authenticator's response.
Source
Thrown at packages/core/src/lib/actions/callback/oauth/checks.ts:270
async use(
options: InternalOptions<WebAuthnProviderType>,
cookies: RequestInternal["cookies"],
resCookies: Cookie[]
): Promise<WebAuthnChallengePayload> {
const cookieValue = cookies?.[options.cookies.webauthnChallenge.name]
const parsed = await parseCookie("webauthnChallenge", cookieValue, options)
const payload = await decode<WebAuthnChallengePayload>({
secret: options.jwt.secret,
token: parsed,
salt: webauthnChallengeSalt,
})
// Clear the WebAuthn challenge cookie after use
clearCookie("webauthnChallenge", options, resCookies)
if (!payload) throw new InvalidCheck("WebAuthn challenge was missing")
return payload
},
}
View on GitHub (pinned to a1a16a5a77)
Solutions
- Ensure the client sends credentials with every Auth.js request (fetch with credentials: "include" / axios withCredentials).
- Verify cookies survive in the target browser; test outside private mode and check SameSite/Secure settings relative to AUTH_URL.
- Make sure the WebAuthn challenge and verification hit the same origin/host configured in AUTH_URL.
- If building a native client, implement a cookie jar that persists the webauthnChallenge cookie across the two requests.
- Restart the WebAuthn flow to obtain a fresh challenge.
Example fix
// before: fetch drops cookies
await fetch("/api/auth/callback/webauthn", { method: "POST", body })
// after
await fetch("/api/auth/callback/webauthn", {
method: "POST",
body,
credentials: "include",
}) Defensive patterns
Strategy: validation
Validate before calling
// client-side: ensure cookies are sent with every auth request
const res = await fetch("/api/auth/session", { credentials: "include" })
if (!res.headers.get("set-cookie") && !document.cookie.includes("webauthnChallenge")) {
console.warn("Challenge cookie may not persist; check SameSite/credentials")
} Try / catch
try {
await signIn("webauthn", { challenge })
} catch (e) {
if (e?.message?.includes("WebAuthn challenge was missing")) {
// restart the WebAuthn flow to get a fresh challenge cookie
}
} Prevention
- Send credentials: "include" on all auth fetch calls
- Test passkey flows in Safari/ITP browsers where cookies are partitioned
- For native/mobile clients, persist the challenge cookie in a cookie jar
- Keep the challenge and verification requests on the same origin as AUTH_URL
When it happens
Trigger: During WebAuthn sign-in or registration verification, the webauthnChallenge cookie is absent or undecodable (decode returns falsy payload) when use() runs after clearing the cookie. Commonly caused by the browser not storing/sending the cookie between the challenge request and the authenticate response.
Common situations: Cross-site (Safari/ITP) or third-party cookie blocking dropping the challenge cookie; API clients (mobile apps, fetch without credentials: 'include') that don't persist cookies; AUTH_URL/origin mismatch invalidating Secure cookies; challenge issued on a different domain than verification.
Related errors
- WebAuthn authentication response could not be verified
- Missing user registration data in WebAuthn challenge cookie
- Authenticator not found.
- Authenticator not found.
- Authenticator not found.
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/15d7a490a8f453b7.
Report an issue: GitHub.