medusajs/medusa · error · AuthCallbackError

resolveProvisionError(error, t)

Error message

resolveProvisionError(error, t)

What it means

When a user authenticates via SSO in the admin dashboard, a JWT token is exchanged and then used to provision (find or create) the local admin user. If the provisioning step (ensureUser) fails for any reason — expired token, missing invite, invalid role, or a backend rejection — the raw error is passed through resolveProvisionError(error, t) which maps it to a translated, user-friendly message and rethrows it as an AuthCallbackError to be shown as a toast on the login screen.

Source

Thrown at packages/admin/dashboard/src/routes/login/components/sso-login.tsx:235

              navigate("/login")
            }
          })
          return
        }

        if (typeof result === "object" && "verification_required" in result) {
          throw new Error("Verification required but not implemented yet")
        }

        token = result
      } catch (error) {
        throw new AuthCallbackError(t("auth.login.authenticationFailed"))
      }

      try {
        await ensureUser(token)
      } catch (error) {
        throw new AuthCallbackError(resolveProvisionError(error, t))
      }

      navigate("/")
    } catch (error) {
      toast.error(
        error instanceof AuthCallbackError
          ? error.message
          : t("auth.login.authenticationFailed")
      )
      // Navigate to /login without the query string, otherwise a failed
      // callback would get stuck on the spinner. There's no point in keeping the
      // query string anyway because the callback would just fail again.
      navigate("/login")
    }

    setIsPending(false)
  }, [providerId, searchParams, t, onMfaChallenge, ensureUser, navigate])

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Check the browser network tab for the failing request following the token exchange (typically a call to /auth/user/me or the user create endpoint) and read its response body for the underlying cause
  2. If the user does not yet exist in Medusa, create an invite (POST /admin/invites) and have the user log in again, or provision the user via the provider first
  3. Verify the auth provider configuration (client ID, secret, redirect/callback URL) in medusa-config and that the token is still valid when the callback fires
  4. Retry the login from the sign-in screen; if it persists, inspect server logs for the exception thrown by ensureUser

Example fix

// before
try {
  await ensureUser(token)
} catch (error) {
  throw new AuthCallbackError(resolveProvisionError(error, t))
}

// after (ensure the user is invited/provisioned first)
// POST /admin/invites { email: "user@example.com", role: "member" }
// then retry the SSO login so ensureUser(token) succeeds
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  await handleCallback()
} catch (error) {
  if (error instanceof AuthCallbackError) {
    // already translated user-facing message from resolveProvisionError
    toast.error(error.message)
  } else {
    toast.error("Unexpected error during SSO login")
    console.error(error)
  }
}

Prevention

When it happens

Trigger: Completing an SSO/OIDC callback in the admin dashboard where the auth provider returns a token but the subsequent ensureUser(token) call fails: e.g. the token is rejected by the /auth/user/me or user-creation endpoint, the user is not invited/created in Medusa, or the provider token lacks required claims.

Common situations: First-time SSO login before an admin invite has been accepted; the identity provider's token expired between redirect and callback; misconfigured auth provider (wrong client id/secret/redirect URI); a user authenticates successfully upstream but is not provisioned as an admin user in Medusa.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/bd9a1749ecc54df1. Report an issue: GitHub.