nextauthjs/next-auth · error · AuthError
Invalid action parameter
Error message
Invalid action parameter
What it means
AuthError('Invalid action parameter') is thrown by the WebAuthn callback handler when the request body's `action` field is not exactly the string "authenticate" or "register". The webauthn callback route supports only these two actions, and anything else is rejected before any adapter or provider work happens.
Source
Thrown at packages/core/src/lib/actions/callback/index.ts:398
const sessionCookies = sessionStore.chunk(newToken, {
expires: cookieExpires,
})
cookies.push(...sessionCookies)
}
await events.signIn?.({ user, account })
return { redirect: callbackUrl, cookies }
} else if (provider.type === "webauthn" && method === "POST") {
// Get callback action from request. It should be either "authenticate" or "register"
const action = request.body?.action
if (
typeof action !== "string" ||
(action !== "authenticate" && action !== "register")
) {
throw new AuthError("Invalid action parameter")
}
// Return an error if the adapter is missing or if the provider
// is not a webauthn provider.
const localOptions = assertInternalOptionsWebAuthn(options)
// Verify request to get user, account and authenticator
let user: User
let account: Account
let authenticator: Authenticator | undefined
switch (action) {
case "authenticate": {
const verified = await verifyAuthenticate(
localOptions,
request,
cookies
)
user = verified.userView on GitHub (pinned to a1a16a5a77)
Solutions
- Send action: "authenticate" or action: "register" (exact lowercase strings) in the JSON body of the webauthn callback request
- Use the official @auth/core browser helpers (e.g. webAuthnFP routines in auth-client) instead of hand-crafted requests
- Confirm the request has Content-Type: application/json and a serialized body so request.body?.action is populated
- Align client package version with the @auth/core version to avoid protocol drift
Example fix
// before
await fetch("/api/auth/callback/webauthn", { method: "POST" })
// after
await fetch("/api/auth/callback/webauthn", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "authenticate", ...assertion })
}) Defensive patterns
Strategy: validation
Validate before calling
const action = body.action
if (action !== "authenticate" && action !== "register") {
throw new Error(`Invalid webauthn action: ${action}`)
} Type guard
function isWebAuthnAction(a: unknown): a is "authenticate" | "register" {
return a === "authenticate" || a === "register"
} Try / catch
try {
await webAuthnAction({ action: "authenticate", assertion })
} catch (e) {
if ((e as Error).message.includes("Invalid action parameter")) {
// fix request payload: action must be 'authenticate' or 'register'
}
} Prevention
- Use the official auth client helpers instead of hand-rolled fetch calls to the webauthn callback
- Keep client and @auth/core versions in sync
- Always send JSON with Content-Type: application/json
- Validate action strings in your client before POSTing
When it happens
Trigger: POSTing to /api/auth/callback/webauthn with body.action missing, undefined, a non-string value, or a typo such as "login"/"signup" instead of "authenticate"/"register".
Common situations: Custom WebAuthn client code calling the internal endpoint directly with a wrong action name; a library version mismatch where the client sends an older action vocabulary; hand-rolled fetch calls forgetting JSON.stringify({ action }) so the body parses without an action field.
Related errors
- credential id is required
- No user id.
- 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/15cde4c8d3371a50.
Report an issue: GitHub.