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.user

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Send action: "authenticate" or action: "register" (exact lowercase strings) in the JSON body of the webauthn callback request
  2. Use the official @auth/core browser helpers (e.g. webAuthnFP routines in auth-client) instead of hand-crafted requests
  3. Confirm the request has Content-Type: application/json and a serialized body so request.body?.action is populated
  4. 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

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


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/15cde4c8d3371a50. Report an issue: GitHub.