Join our Newsletter — 33% off our NHI Course
Home› Guides› JWT Client Authentication (private_key_jwt) Guide: Replacing Client Secrets…
Guide Non-Human Identity (NHI)

JWT Client Authentication (private_key_jwt) Guide: Replacing Client Secrets with Keys

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 27 October 2026 15 min read
On this page

Most OAuth clients still prove who they are with a client secret, a shared password that is copied into config files, pipelines and vaults and works for anyone who finds it. JWT client authentication, registered in OAuth as private_key_jwt, replaces that secret with a short-lived assertion signed by a private key that never leaves the client. It is defined by RFC 7523, recommended by the OAuth Security Best Current Practice (RFC 9700) and required, alongside mutual TLS, by the FAPI 2.0 Security Profile. This guide explains how the mechanism works, what the authorisation server must validate, the audience change introduced by the RFC 7523 update, how to manage the client's keys and how to migrate a fleet of confidential clients off secrets. It is written for identity engineers, platform teams and anyone who owns machine-to-machine integrations.

Key takeaways

  • A signed assertion is not a password. The authorisation server holds only the client's public key, so a database leak or a copied log line no longer hands out a reusable credential.
  • Set the audience to the issuer identifier. The RFC 7523 update (draft-ietf-oauth-rfc7523bis) makes the issuer the only permitted aud for client authentication, closing the audience injection class of attacks.
  • Keep assertions short and single use. Expiry of a few minutes, a unique jti and server-side replay tracking turn a stolen assertion into a near-worthless artefact.
  • The private key is now the crown jewel. Generate it in a KMS or HSM where you can, publish the public half through jwks_uri and rotate by overlapping keys rather than swapping them.
  • Migrate in rings and then switch secrets off. A client that can still fall back to client_secret_basic has not been hardened; the last step is removing the secret and refusing the old method.

Why client secrets are the weak point

A client secret is a symmetric credential. Both sides know it, it is presented on every token request, and anything that can read it can impersonate the client. In practice it ends up in environment variables, CI variables, helm values, wiki pages and support tickets, and RFC 7591 even allows client_secret_expires_at to be 0, meaning the secret never expires. The NHI Authentication Guide covers the wider choice of machine credentials; this page goes deep on one of the strongest options for OAuth clients.

  • Exposure on use: a secret sent in client_secret_basic or client_secret_post crosses every proxy and logging layer on the way to the token endpoint. A signed assertion also crosses them, but it expires in minutes and is bound to one audience.
  • Exposure at rest on the server: the authorisation server must store something that verifies the secret. With private_key_jwt it stores a public key, which is not sensitive.
  • Theft techniques: attackers harvest secrets from files and repositories (MITRE ATT&CK T1552.001 Credentials In Files) and add their own credentials to existing applications (T1098.001 Additional Cloud Credentials). Both are easier when the credential is a copyable string.
  • What the standards say: RFC 9700 Section 2.5 states that it is RECOMMENDED to use asymmetric cryptography for client authentication, naming mutual TLS and private_key_jwt as examples.

Client authentication methods compared

Method (token_endpoint_auth_method)Credential the client holdsWhat the server storesMain weaknessTypical fit
client_secret_basic / client_secret_postShared secretSecret or its hashReplayable string, sent on every requestLegacy integrations, low-risk internal tools
client_secret_jwtShared secret used as an HMAC keyThe secret itself (needed to verify the MAC)Still symmetric: a server-side leak exposes itRarely the right choice today
private_key_jwtPrivate key (RSA or EC)Public key or jwks_uriPrivate key theft from the workload; audience mistakesServer-side apps, M2M, FAPI ecosystems, multi-cloud
tls_client_auth (RFC 8705)Private key plus CA-issued certificateExpected subject DN or SANNeeds PKI and TLS termination that passes the certificateOrganisations with mature PKI, open banking
self_signed_tls_client_auth (RFC 8705)Private key plus self-signed certificateCertificate in the client's JWKS (x5c)Same TLS plumbing, no chain validationmTLS without running a CA
Workload identity federationPlatform-issued token (Kubernetes, CI, cloud)Trust policy for the external issuerTrust policy too broad (wildcard subjects)Workloads on platforms that issue identity tokens

Choosing: pick private_key_jwt when TLS termination makes mutual TLS awkward (load balancers, API gateways, SaaS token endpoints) or when one client talks to several authorisation servers. Pick mutual TLS when you already run a PKI and want the same certificate to sender-constrain tokens. Pick federation when the platform already gives the workload a verifiable identity, which removes even the long-lived private key. See the mTLS Guide and the Machine-to-Machine OAuth (Client Credentials) Guide.

How private_key_jwt works

  1. Registration: the client registers token_endpoint_auth_method=private_key_jwt and either a jwks_uri or an inline jwks (RFC 7591 says the two MUST NOT both be present, and prefers jwks_uri because it allows easier key rotation).
  2. Discovery: the client reads the authorisation server metadata (RFC 8414) at /.well-known/oauth-authorization-server or the OpenID equivalent, checks that private_key_jwt appears in token_endpoint_auth_methods_supported, and picks an algorithm from token_endpoint_auth_signing_alg_values_supported. RFC 8414 requires that list when private_key_jwt is advertised and forbids none in it.
  3. Assertion: for each request the client builds a fresh JWT, signs it with its private key and sends it as client_assertion with client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer. RFC 7523 allows exactly one JWT in that parameter.
  4. Validation: the server finds the client's key (by kid), verifies the signature, checks the claims and only then processes the grant. A bad assertion returns invalid_client (RFC 7523 Section 3.2).

The same assertion format is used wherever the client authenticates to the server: token, pushed authorisation request (PAR), introspection and revocation endpoints. RFC 8414 has matching *_auth_methods_supported metadata for each.

Assertion claims and header

FieldValue for client authenticationSource and notes
issThe client_idRFC 7523 Section 3, required
subThe client_idRFC 7523: for client authentication the subject MUST be the client_id
audThe authorisation server's issuer identifier, as a single stringdraft-ietf-oauth-rfc7523bis; FAPI 2.0 5.3.3.1 item 05 says a string, not an item in an array
expA few minutes after issueRequired. Microsoft Entra documentation advises 5 to 10 minutes after nbf at most
iat, nbfCurrent timeOptional in RFC 7523; servers may reject values unreasonably far in the past. FAPI 2.0 accepts up to 10 seconds of future clock skew
jtiUnique random identifierOptional in RFC 7523 but needed for replay detection; treat it as mandatory in your own profile
Header algPS256, ES256 or EdDSAFAPI 2.0 Section 5.4.1 list; never none
Header kidIdentifier of the signing keyLets the server pick the right key during rotation
Header typclient-authentication+jwtSHOULD in the rfc7523bis draft; servers are advised not to reject untyped JWTs yet

The audience change in RFC 7523bis

RFC 7523 allowed the audience to be the token endpoint URL and left the exact strings to be agreed out of band. Researchers at the University of Stuttgart (Hosseyni, Küsters and Würtele, IACR ePrint 2025/629, "Audience Injection Attacks") showed that when a client signs assertions whose audience is an endpoint value it learnt from metadata, a malicious authorisation server can supply values that make the client mint an assertion usable at an honest server. The paper lists OAuth 2.0, OpenID Connect, FAPI, CIBA and the device authorisation grant among the affected standards. The issue was disclosed to the OAuth Working Group in January 2025.

  • What the update says: draft-ietf-oauth-rfc7523bis (version -11, with the RFC Editor and marked "blocked: Final Approval Pending" when checked on 27 October 2026) makes the issuer identifier the only permitted audience for client authentication JWTs, says the token endpoint URL MUST NOT be used as an audience value, and requires the server to reject any JWT that does not contain its issuer identifier as its sole audience value.
  • Knock-on changes: the draft also updates RFC 7521, RFC 7522 and RFC 9126 (PAR) so the same rule applies to assertions sent to the PAR endpoint. Authorisation grants (RFC 7523 Section 2.1) still allow either the issuer or the token endpoint URL.
  • FAPI 2.0 already requires it: Section 5.3.2.1 item 08 says the server shall only accept its issuer identifier as a string in the aud claim.
  • Vendor reality: some providers still document the token endpoint URL as the audience. Microsoft Entra, for example, documents https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token. Follow the provider's documented value until it changes, and track the change.

Because the draft is not yet an RFC, check its final text before writing it into policy; the core audience rule has been stable across recent versions.

What the authorisation server must validate

  • Method lock: accept only the authentication method registered for that client. A client registered for private_key_jwt must not be able to fall back to a secret.
  • Key source: resolve keys only from the client's registered jwks or jwks_uri. Ignore jku, x5u and embedded jwk headers in the assertion (FAPI 2.0 Section 5.4.2 advises against jku and x5u; ASVS 5.0 V9.1.3 requires key material from trusted pre-configured sources).
  • Algorithm allowlist: pin the accepted alg values per client or per server and reject none and HMAC algorithms for this method.
  • Claims: iss and sub equal the client_id; aud is exactly the issuer identifier; exp is in the future and not unreasonably far away (reject lifetimes over a few minutes); iat and nbf sit inside a small skew window.
  • Replay: store each jti until the assertion's exp and reject repeats. RFC 7523 treats replay protection as optional; high-assurance profiles should not.
  • Key strength: RSA keys of at least 2048 bits and elliptic curve keys of at least 224 bits (FAPI 2.0 Section 5.4).
  • JWKS fetching: fetch the client's jwks_uri over TLS, cache with a sensible maximum age, refetch on an unknown kid with rate limiting, and restrict outbound fetches so the URI cannot be pointed at internal addresses.

Managing the client's private key

OptionHow signing worksStrengthTrade-off
Cloud KMS or HSM key (non-exportable)Workload calls the KMS sign API; key never leavesTheft needs live access to the workload's KMS permissionLatency and cost per signature; KMS permission becomes the credential to guard
Secrets manager holding a PEM keyWorkload fetches key at start-up and signs locallyCentral rotation and audit of readsKey exists in process memory and can be copied
Key generated on the workload, public half registeredKey created at deploy time, never stored elsewhereNo copy outside the hostNeeds automated registration of the new public key
Key file in the repository or imageSigns locallyNone worth havingSame exposure as a client secret: avoid
  • One key per client, per environment: never share a key across clients or between production and test.
  • Prefer jwks_uri: it lets the client publish the next key before using it, which is the basis of zero-downtime rotation. See the JSON Web Key Sets and Signing Key Rotation Guide for the overlap pattern.
  • Rotation cadence: rotate on a schedule (for example yearly for KMS-held keys, more often for exported keys) and immediately on suspected exposure. Rotation means publish new key, start signing with it, then remove the old one after caches expire.
  • Ownership: record an owner, environment and expiry for every client key in your NHI inventory, as you would for any credential. See the Cryptographic Key Management Guide.

Migrating from client secrets: a phased rollout

  1. Inventory: list every confidential client, its current token_endpoint_auth_method, secret age and expiry, owner and the endpoints it calls. Flag secrets with no expiry first.
  2. Confirm server support: check the provider's metadata for private_key_jwt and its supported algorithms, and confirm how it handles aud (issuer or token endpoint) and jti replay.
  3. Build one signing library: wrap assertion creation in a shared library or sidecar that sets claims correctly, uses a fresh jti, keeps exp short and calls the KMS. Most failures come from hand-rolled assertion code.
  4. Pilot ring: register a public key alongside the existing secret for a handful of low-risk clients, switch them to assertions, and watch token endpoint errors (invalid_client) and clock-skew rejections for a week.
  5. Wider rings: move clients by business criticality, highest-risk scopes first once the pattern is proven. Keep the secret valid but unused during each ring as the rollback path.
  6. Remove the fallback: delete the secret, change the registered method so the server refuses secrets for that client, and alert on any secret-based attempt.
  7. Rollback: if a ring fails, re-enable the secret method for the affected clients only, fix the signing library, and repeat. Never roll back by re-issuing a new long-lived secret broadly.

Small organisations with a single identity provider can often finish in weeks by switching clients one at a time. Large estates with many providers should standardise the library first and track progress as a percentage of clients without secrets.

Detection and measurement

  • Log fields: on every token request record client_id, authentication method, kid, jti, source IP and result. Correlate with the KMS sign logs for the same client.
  • Alerts: a secret-based attempt for a client registered for private_key_jwt; repeated jti values; a new key added to a client's registration outside change control (this maps to T1098.001); assertions signed with a kid that is no longer published; token requests from networks the client never uses.
  • Registration changes: review every change to client credentials. Unreviewed application credentials were part of the path in the Microsoft Midnight Blizzard breach, where a legacy test OAuth application and newly created OAuth apps gave the attacker mailbox access.
MetricTarget
Confidential clients using asymmetric authentication (private_key_jwt or mTLS)Rising to 100% of production clients
Clients that still hold a valid secret after migrationZero
Median assertion lifetime (exp minus iat)5 minutes or less
Client keys held in non-exportable KMS or HSM storageAbove 80% for production
Client keys older than the rotation policyZero
Replayed jti rejections investigated within one working day100%

Framework mapping

FrameworkReferenceHow private_key_jwt helps
NIST SP 800-53 Rev. 5IA-9 Service Identification and AuthenticationCryptographic authentication of the client service to the token service
NIST SP 800-53 Rev. 5IA-5 Authenticator ManagementKey generation, rotation and protection replace shared secret handling
NIST SP 800-53 Rev. 5SC-12 Cryptographic Key Establishment and ManagementLifecycle of the client's signing key
NIST CSF 2.0PR.AA-01, PR.AA-03Credentials for services are managed; services are authenticated
OWASP ASVS 5.0V10.4.10, V10.4.16Confidential clients authenticated on back-channel requests using strong, public-key based methods
MITRE ATT&CKT1552.001, T1528, T1098.001Removes copyable secrets; key additions become a detectable event
FAPI 2.0 Security Profile5.3.2.1 items 06 and 08Client authentication restricted to mTLS or private_key_jwt with issuer audience

Common failure patterns

  • Secret left as a fallback: the client signs assertions, but the old secret still works, so an attacker simply uses the secret. Removing the method is the step that delivers the security gain.
  • Long-lived assertions: code that mints one assertion with a 24-hour exp and reuses it has rebuilt a bearer secret. Mint per request.
  • Private key stored like a secret: a PEM file in the repository or container image gives no advantage over a client secret. Leaked keys in images are common, as the Docker Hub Secrets Leak 2025 showed for many kinds of credential.
  • Trusting header-supplied keys: a server that honours jku or an embedded jwk lets the attacker choose the verification key. Resolve keys only from registration.
  • Audience as an array of endpoints: clients that put several endpoint URLs in aud, or servers that accept any of them, are exactly the pattern the audience injection research exploited.
  • No replay store: without jti tracking, an assertion captured from a debug log can be replayed until it expires.

Practitioner checklist

  • Inventory confidential clients and record method, secret age, owner and scopes.
  • Confirm each authorisation server advertises private_key_jwt and an algorithm list without none.
  • Use one shared signing library that sets iss, sub, issuer aud, short exp and a fresh jti.
  • Generate production client keys in KMS or HSM storage; one key per client per environment.
  • Register keys through jwks_uri where possible and rotate by overlap.
  • On the server, pin algorithms, ignore jku, x5u and jwk headers, and track jti until expiry.
  • Migrate in rings, keep the secret as a rollback path per ring, then delete it and lock the method.
  • Alert on secret attempts, replayed jti values and unplanned key additions.
  • Track the rfc7523bis draft and update audience handling when providers change.

Standards and references

Related NHI Mgmt Group resources: NHI Authentication Guide · Azure Entra Client Secrets Security Guide · JSON Web Key Sets and Signing Key Rotation Guide · FAPI 2.0 Security Profile Implementation Guide · OAuth 2.0 Security Best Current Practice Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 27 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org