# `Ankusa.Admin.Auth.JWT`
[🔗](https://github.com/jamescarr/ankusa/blob/ankusa-v0.7.0/packages/ankusa/lib/ankusa/admin/auth/jwt.ex#L1)

OIDC / OAuth2 bearer tokens (`mode: :jwt`): the control planes accept the
access tokens your identity provider issues, so operators sign in with SSO
and revocation is the provider's.

    jwt: %{
      issuer: "https://login.example.com/",
      audience: "ankusa-admin",
      jwks_url: "https://login.example.com/.well-known/jwks.json"
    }

A token is accepted when all of these hold:

  * it is a JWS signed with an asymmetric algorithm (`RS*`, `PS*`, `ES*`,
    `EdDSA`) by a key of the configured set. `none` and the `HS*` family are
    never accepted, so a token cannot be forged by presenting a public key
    as an HMAC secret;
  * `iss` equals `jwt.issuer` and `aud` is, or contains, `jwt.audience` (or
    one of its entries, when that is a list);
  * `exp` is present and not past, and `nbf`, when present, is not ahead,
    each with `jwt.leeway_s` seconds of clock-skew leeway;
  * `sub` names the caller (it becomes the principal's id).

The principal's scopes come from the `jwt.scope_claim` claim (default
`scope`: a space-delimited string as in RFC 9068, or a list), and its tenants
from `jwt.tenants_claim` (default `ankusa_tenants`: a list of tenant ids, or
`["*"]`) together with any `tenant:<id>` scopes. Scopes this system does not
define (`openid`, `email`) are ignored.

Keys come from `jwt.keys` (public JWKs or PEMs), from `jwt.jwks_url`, or
both; see `Ankusa.Admin.Auth.JWT.Keys` for how the JWKS is cached and
refreshed. With no key loaded every token is `401`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
