# Auth0

> Auth0 AuthStrategy — verifies Auth0-issued JWTs via the tenant's JWKS (no client secret) and maps a namespaced custom claim → tenantId.



---

<!-- source: en/plugins/auth-auth0.md -->
## Auth0

_Auth0 AuthStrategy — verifies Auth0-issued JWTs via the tenant's JWKS (no client secret) and maps a namespaced custom claim → tenantId._

`@voltro/plugin-auth-auth0` integrates [Auth0](https://auth0.com): an `AuthStrategy` (conforming to `@voltro/protocol`) that verifies Auth0-issued JWTs against the tenant's **JWKS endpoint** (public-key verify — no client secret), maps a namespaced custom claim to the framework's `tenantId`, and composes with other strategies (your password cookie, an API key, another IdP). It's a thin specialization of the shared `jwtBearerStrategy` — it adds Auth0's defaults and performs no verification of its own. Verified claims arrive on the Subject as `metadata.provider === 'auth0'` + `metadata.claims`.

## Install

```
pnpm add @voltro/plugin-auth-auth0
```

## Wiring

Add `auth0Strategy(...)` to `auth.strategies` in your api's `app.config.ts`. The built-in signed-cookie password strategy always runs first; your strategies run after it, in order, until one `matched`s (or one `failed`s).

```ts
// app.config.ts
import { auth0Strategy } from '@voltro/plugin-auth-auth0'

export default {
  type: 'api' as const,
  name: 'myApi',
  store: 'postgres' as const,
  auth: {
    strategies: [
      auth0Strategy({
        domain:   'acme.us.auth0.com',                 // required — builds JWKS URL + issuer
        audience: 'https://api.acme.com',              // your API identifier
        // tenantClaim: 'https://voltro.dev/tenant',    // default namespaced URN
        // defaultTenantId: 'public',                   // fallback for single-tenant setups
        // scopesFromClaims: (c) => c.permissions ?? [], // Auth0 RBAC permissions → scopes
      }),
    ],
  },
}
```

`domain` is the only required option (protocol + trailing slash are stripped). From it: JWKS URL defaults to `https://<domain>/.well-known/jwks.json` and issuer to `https://<domain>/` — **the trailing slash matters for Auth0** (override `issuer` for a custom domain).

Tenant resolution maps from `tenantClaim` (default the namespaced URN `https://voltro.dev/tenant` — Auth0's rules require non-standard claims to live under a URN). Use a custom Auth0 Action to copy your app metadata into the namespaced claim, or point `tenantClaim` at an unnamespaced field that already exists in your token. Supply `tenantIdFromClaims(claims)` to derive it (returning `null` is a `failed` verdict). `scopesFromClaims` maps verified claims (the `permissions` array with RBAC enabled, or the space-delimited `scope` claim) onto `Subject.scopes`.

To accept your own password sessions AND Auth0 during a migration, build the chain explicitly with `composeAuthStrategies` (see [auth strategies](/docs/authentication/strategies)):

```ts
import { composeAuthStrategies } from '@voltro/protocol'
import { voltroPasswordStrategy } from '@voltro/plugin-auth'
import { auth0Strategy } from '@voltro/plugin-auth-auth0'

const resolve = composeAuthStrategies([
  voltroPasswordStrategy(),
  auth0Strategy({ domain: process.env.AUTH0_DOMAIN!, audience: process.env.AUTH0_AUDIENCE! }),
])
```

## Options

| Option | Default | Notes |
|---|---|---|
| `domain` | — (**required**) | e.g. `acme.us.auth0.com`. Builds JWKS URL + issuer. |
| `audience` | (off) | Your API identifier. String or array. |
| `jwksUrl` | `https://<domain>/.well-known/jwks.json` | Override. |
| `issuer` | `https://<domain>/` | Trailing slash matters; override for custom domains. |
| `cookieName` | `null` (header-only) | Auth0's hosted flow uses Bearer tokens. |
| `tenantClaim` | `'https://voltro.dev/tenant'` | Namespaced URN. |
| `tenantIdFromClaims` | (uses `tenantClaim`) | Derive `tenantId`; `null` → `failed`. |
| `defaultTenantId` | (none) | Fallback for single-tenant setups. |
| `scopesFromClaims` | (none) | Map claims → `Subject.scopes`. |

Algorithms are pinned to `['RS256']` (no alg-confusion).

## Environment variables

None read directly — pass `domain` / `audience` explicitly (typically from your own `defineEnv`-declared vars).

## Security

Server-only; fails closed — a forged, expired, or wrong-audience token, or one with no resolvable tenant, yields `failed`, never `matched`. JWKS public-key verify only; no Auth0 client secret is ever handled.

## See also

- [External identity providers](/docs/authentication/external-idp)
- [Auth plugin](/docs/plugins/auth)
