JWT-Bearer (RFC 7523) lets a client or workload prove its identity using a
signed JWT instead of a shared secret. theauth-go v2.4 adds two related
features:
- JWT-Bearer client authentication: substitute a signed JWT for
client_secret in any token request.
- JWT-Bearer grant: exchange an external JWT (e.g., a Kubernetes
ServiceAccount token) for a theauth access token directly, without an
interactive authorization code flow.
The headline use case: Kubernetes workload identity
A Kubernetes Pod running in a namespace has a projected ServiceAccount token
automatically mounted at /var/run/secrets/kubernetes.io/serviceaccount/token.
This token is signed by the cluster’s OIDC issuer. With JWT-Bearer:
No secrets need to be distributed to the Pod. The Kubernetes OIDC issuer serves
as the root of trust.
TrustedJWTIssuer and SubjectMapper
Configure one or more trusted external JWT issuers:
SubjectMapper is an interface (Resolve(claims map[string]any) (ULID, error)),
not a plain function value. It receives the full claims map and returns the
local user ULID the assertion should authenticate as. Return
theauth.ErrStorageNotFound to deny without error detail leakage. Return any
other non-nil error to surface an invalid_grant error response. Use the
built-in theauth.SubMapper{} (parses sub as a ULID directly) or
theauth.EmailMapper{Lookup: ...} (looks up by the email claim) when a
custom mapper isn’t needed.
JWT-Bearer grant
The AS:
- Decodes the
assertion JWT (no verification yet).
- Looks up the
iss claim in TrustedIssuers.
- Fetches (or uses the cached) JWKS from
JWKSU and verifies the signature.
- Calls
SubjectMapper to resolve a client_id.
- Looks up the resolved client and applies its allowed scopes and resources.
- Mints a theauth access token bound to the resolved
resource.
The response follows the standard token response shape:
JWT-Bearer client authentication
Instead of (or in addition to) the grant flow, a client can use a JWT to
authenticate on any grant type:
The JWT must be signed with the private key corresponding to the public key
registered for my-client (via jwks_uri or inline jwks on the client
registration). The AS verifies the signature, iss == client_id, aud == AS issuer, exp, iat, nbf, and a one-time jti (replay prevention
within the AccessTokenTTL window).
This replaces client_secret entirely. No shared secret needs to be
distributed or rotated.
Combining with PAR + JAR (FAPI 2.0)
When JWT-Bearer client authentication is combined with PAR and JAR:
- The client pushes a signed authorization request to
/oauth/par (JAR inside
PAR).
- The client authenticates on the token endpoint using a JWT client assertion
(JWT-Bearer client auth).
- PKCE S256 is enforced (default in theauth-go).
This combination meets the FAPI 2.0 Security Profile baseline. See
PAR + JAR for the flow diagrams.
Configuration reference
Set AuthorizationServerConfig.JWTBearer to enable; nil disables the feature.
See also
Last modified on October 7, 2026