flashman
← All guides

OAuth JWT bearer client assertions

Issue OAuth JWT bearer client assertions with pinned audiences, short lifetimes, unique identifiers, signing-key rotation, and token-endpoint checks that fail closed.

2026-09-29 · 8 min read

  • oauth
  • jwt
  • security

OAuth private-key JWT client authentication and the JWT bearer grant both present a signed JWT to the token endpoint. The assertion identifies the client and is checked for issuer, subject, audience, lifetime, and signature before the authorization server issues a token.

An assertion is a credential. Keep its lifetime short, bind it to the token endpoint that should accept it, and store enough replay state to reject a captured JWT that an attacker resubmits.

Bind the assertion to one token endpoint

Read the authorization server metadata and the client's registered authentication method. Set the audience to the exact value that server requires, commonly the token endpoint URL or the issuer identifier, and reject configuration that copies an API audience into the assertion.

  • Match iss and sub to the registered client identifier.
  • Pin aud to the documented token-endpoint value.
  • Use a dedicated signing key for client authentication.
  • Keep authorization-server environments on separate keys.

Keep lifetimes and replay windows small

Set iat to the time the assertion is minted and exp only far enough ahead to absorb normal clock skew and a single token request. A long-lived assertion is a bearer secret that can be replayed until it expires.

Include a unique jti when the server supports replay detection, and do not reuse an assertion across processes or retries unless the profile you implement explicitly allows that reuse.

Rotate signing keys without an outage

Publish the new public key, wait until the authorization server can select it by kid, then switch the signer. During overlap, sign with one current key and keep the previous key only for verification if you also validate assertions locally.

Reject unexpected algorithms, including none, and prefer the algorithm registered for that client. A kid that points at the wrong key family should fail rather than fall through to a shared verification set.

Fail closed at the token endpoint

The token endpoint should validate the signature, issuer binding, audience, time claims, and client registration before it looks at requested scopes or grants. Error responses can name the class of failure without echoing the assertion or the private material that signed it.

Distinguish client authentication from the JWT bearer grant in logs and metrics. They can share signing code and still require different audience and subject rules.

Test claims, keys, and clocks

Use Flashman's JWT decoder for synthetic assertions, the timestamp converter for iat, nbf, and exp, the JSON formatter for token errors, the URL parser to compare audiences with the token endpoint, and the hash tool when you fingerprint a public test key.

Cover wrong audiences, expired and early assertions, reused identifiers, algorithm confusion, key rotation, issuer and subject swaps, clock skew, and both client authentication and the grant if the deployment uses both.

Try these tools