medusajs/medusa · error · MedusaError

The identity provider did not return an ID token; ensure the

Error message

The identity provider did not return an ID token; ensure the 'openid' scope is requested

What it means

After a successful token exchange, the engine requires an ID token (tokenSet.id_token) to extract claims. Without the openid scope the provider returns only access/refresh tokens and claims() would throw an unhelpful TypeError, so the engine fails fast with UNAUTHORIZED and an explicit hint.

Source

Thrown at packages/modules/providers/auth-oidc/src/engine/engine.ts:178

      // Forward every authorization-response parameter so
      // openid-client can enforce all applicable checks. The `checks` argument
      // carries the values we stored ourselves (PKCE verifier, nonce, state).
      tokenSet = await client.callback(redirectUri, params, {
        code_verifier: input.codeVerifier,
        nonce: input.nonce,
        state: input.state,
      })
    } catch (error) {
      throw new MedusaError(
        MedusaError.Types.UNAUTHORIZED,
        `Could not validate the identity provider's response: ${error.message}`
      )
    }

    // Without the `openid` scope, the token endpoint returns no ID token and
    // `tokenSet.claims()` would throw an unhelpful TypeError.
    if (!tokenSet.id_token) {
      throw new MedusaError(
        MedusaError.Types.UNAUTHORIZED,
        "The identity provider did not return an ID token; ensure the 'openid' scope is requested"
      )
    }

    const claims = tokenSet.claims()

    return {
      claims: { ...claims },
      tokens: {
        id_token: tokenSet.id_token,
        access_token: tokenSet.access_token,
        refresh_token: tokenSet.refresh_token,
        expires_at: tokenSet.expires_at,
        token_type: tokenSet.token_type,
        scope: tokenSet.scope,
      },
    }

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Add 'openid' to the authentication scope configuration for the provider (e.g. scope: "openid email profile").
  2. Verify in the IdP console that the client is allowed to request the openid scope.
  3. If the provider is plain OAuth2 (no ID tokens), it cannot be used with this OIDC engine — use a dedicated OAuth2 strategy.

Example fix

// before
options: { issuer: "...", client_id: "...", callback_url: "...", scope: "email profile" }
// after
options: { issuer: "...", client_id: "...", callback_url: "...", scope: "openid email profile" }
Defensive patterns

Strategy: validation

Validate before calling

const scopes = (options.scope ?? "openid").split(" ")
if (!scopes.includes("openid")) {
  throw new Error("OIDC scope must include 'openid' to receive an ID token")
}

Type guard

const requestsOpenidScope = (scope?: string): boolean =>
  (scope ?? "openid").split(/\s+/).includes("openid")

Try / catch

try { await engine.exchangeCode(input) } catch (e) { if (e instanceof MedusaError && /'openid' scope/.test(e.message)) { /* fix scope config, then restart flow */ } throw e }

Prevention

When it happens

Trigger: The provider was configured with a scope list that omits 'openid' (e.g. only 'email profile'), or the IdP app registration does not expose the openid scope, so the token endpoint returns no id_token.

Common situations: A custom scope string like "profile email" in medusa-config.js; using a non-OIDC OAuth2 provider (plain OAuth has no ID tokens); the IdP admin toggled off OpenID Connect for the client.

Related errors


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