medusajs/medusa · error · MedusaError

The email domain is not allowed to authenticate with this pr

Error message

The email domain is not allowed to authenticate with this provider

What it means

When allowed_email_domains is configured, the engine extracts the domain from the mapped email claim and checks membership in the allow-list. An email with no parseable domain or a domain not in the list is rejected with UNAUTHORIZED.

Source

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

    const requireVerifiedEmail = this.options_.require_verified_email ?? true
    if (requireVerifiedEmail && claims.email_verified !== true) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        "The identity provider did not confirm a verified email address"
      )
    }

    if (this.options_.allowed_email_domains?.length) {
      const allowedDomains = this.options_.allowed_email_domains.map((domain) =>
        domain.toLowerCase()
      )
      const domain =
        typeof email === "string"
          ? email.split("@")[1]?.toLowerCase()
          : undefined

      if (!domain || !allowedDomains.includes(domain)) {
        throw new MedusaError(
          MedusaError.Types.UNAUTHORIZED,
          "The email domain is not allowed to authenticate with this provider"
        )
      }
    }

    const userMetadata: Record<string, unknown> = {}
    for (const [field, claimName] of Object.entries(mappings)) {
      if (field === "entity_id" || !claimName) {
        continue
      }
      if (isDefined(claims[claimName])) {
        userMetadata[field] = claims[claimName]
      }
    }

    return {
      entityId: String(entityIdValue),

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Add the user's domain (lowercase, exact) to allowed_email_domains in the provider options.
  2. For subdomain support, list each subdomain explicitly — the check is an exact match, not suffix-based.
  3. If the restriction is unintended, remove the allowed_email_domains option entirely.

Example fix

// before
options: { ..., allowed_email_domains: ["acme.com"] }
// after
options: { ..., allowed_email_domains: ["acme.com", "sub.acme.com"] }
Defensive patterns

Strategy: validation

Validate before calling

const domain = email?.split("@")[1]?.toLowerCase()
if (allowedDomains.length && !allowedDomains.includes(domain)) {
  return res.status(403).json({ error: "email_domain_not_allowed" })
}

Type guard

const isAllowedDomain = (email: string | undefined, allowed: string[]): boolean =>
  !!email && allowed.includes(email.split("@")[1]?.toLowerCase() ?? "")

Try / catch

try { engine.mapClaims(claims) } catch (e) { if (e instanceof MedusaError && e.type === MedusaError.Types.UNAUTHORIZED && /domain is not allowed/.test(e.message)) { res.status(403).json({ error: "email_domain_not_allowed" }); return } throw e }

Prevention

When it happens

Trigger: allowed_email_domains: ["acme.com"] is set and a user authenticates with user@gmail.com, or the mapped email claim is not a string so no domain can be extracted.

Common situations: Restricting a corporate SSO to company domains and users try personal addresses; the allow-list entries have different casing or subdomains (sub.acme.com vs acme.com — only exact lowercase match passes); test users provisioned with an email outside the list.

Understand the failure class

Related errors


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