Client secrets are useful until they become the thing everyone knows how to copy.
That is the quiet risk in many OAuth deployments. A shared secret starts in the client registration. Then it appears in an environment variable, a deployment slot, a local test script, a pipeline variable, an incident note, and sometimes a second application that was only supposed to be temporary. Rotation becomes coordination. Ownership becomes vague. The authorization server can still authenticate the client, but the operational story around that credential has become weak.
The upcoming ProAuth v3 preview adds stronger options for confidential clients that carry higher risk: JWT-based client authentication with private_key_jwt and client_secret_jwt, plus OAuth mutual TLS client authentication with certificate-bound access tokens. These are not cosmetic alternatives to client_secret_basic. They change what the client must prove and, with mTLS token binding, what a resource server can verify when an access token is presented.
Start with the client authentication method
OpenID Connect Core defines client_secret_jwt and private_key_jwt as client authentication methods. Both use a JWT assertion sent with client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer and client_assertion=<signed JWT>. The assertion includes the client as issuer and subject, an audience, an expiration, and a unique jti so the assertion cannot be replayed indefinitely.
The difference is the proof material.
With client_secret_jwt, the client signs the assertion with HMAC using the shared client secret. This avoids sending the secret directly in the request, but it is still a symmetric-secret design. If the secret is copied, the copier can create new valid assertions until the secret is rotated.
With private_key_jwt, the client signs with a private key and ProAuth validates the assertion with the client’s registered public key. In the ProAuth v3 preview, those public keys are configured as Client App Key Sets with usage ClientAssertionSigning; private keys stay with the client. During rotation, teams can register old and new public keys at the same time and let ProAuth select by kid.
That makes private_key_jwt the better fit for high-assurance clients and for ProAuth FAPI 2.0 configuration. The ProAuth docs are explicit on the boundary: use private_key_jwt for FAPI 2.0 clients; client_secret_jwt is not FAPI-compatible.
ProAuth applies the configured method consistently
In the v3 preview, client authentication is configured per client application with tokenEndpointAuthMethod. When a client has an authentication configuration, ProAuth accepts only that configured method for the client. Existing clients without the configuration continue with the legacy secret-based behavior.
That matters because client authentication is not only a token endpoint concern. ProAuth applies JWT client authentication and mTLS client authentication at OAuth endpoints that require client authentication:
- token
- introspection
- revocation
- device authorization
- pushed authorization request (PAR)
For JWT client authentication, each assertion audience must match the endpoint being called. In FAPI mode, ProAuth’s FAPI documentation adds the profile-specific rule that private_key_jwt client assertions use the issuer URL as the assertion audience and must use asymmetric FAPI-compatible algorithms.
The useful operational pattern is simple: decide the method per client, make the allowed method explicit, and rotate the proof material as part of the client’s lifecycle rather than treating it as a long-lived password.
mTLS adds a certificate-backed proof
RFC 8705 defines two OAuth mTLS client authentication methods: tls_client_auth and self_signed_tls_client_auth.
In the ProAuth v3 preview, tls_client_auth is used when the client presents a certificate validated by TLS termination or a trusted ingress. ProAuth checks the certificate validity period and matches the presented certificate against registered subject DN or subject alternative name metadata such as DNS, URI, IP, or email values.
self_signed_tls_client_auth is used when the client presents a self-signed certificate and ProAuth validates the certificate public key against the client’s registered key material. For this mode, ProAuth uses Client App Key Sets with usage SelfSignedTlsClientAuth.
mTLS is stronger in environments where certificate lifecycle is already part of the platform discipline. It is also heavier. Certificate issuance, renewal, trust stores, reverse proxies, endpoint aliases, and forwarded certificate headers become part of the security model.
That last point is easy to understate. ProAuth can read direct TLS client certificates from the request connection. In Kubernetes or reverse-proxy deployments, forwarded client certificates must be enabled per tenant and are disabled by default. Do not enable certificate forwarding unless the ingress strips untrusted incoming certificate headers and sets trusted certificate headers itself after validating the client certificate.
Certificate-bound tokens reduce replay value
mTLS client authentication proves the client at the authorization server. Certificate-bound access tokens add another control at the resource server.
When RequireCertificateBoundAccessTokens is enabled, ProAuth access tokens issued by the token endpoint include a cnf confirmation claim with the SHA-256 thumbprint of the presented client certificate. The RFC 8705 claim name is x5t#S256.
sequenceDiagram
autonumber
participant Client as Confidential client
participant ProAuth as ProAuth
participant API as Resource server
participant Replay as Replay attempt
Client->>ProAuth: Token request with client certificate
ProAuth->>ProAuth: Authenticate client and bind certificate
ProAuth-->>Client: Certificate-bound access token
Client->>API: Token plus matching certificate
API->>API: Compare token binding with certificate
API-->>Client: Accept request
Replay->>API: Copied token without certificate
API-->>Replay: Reject request
For ProAuth’s own OIDC bearer endpoints, such as UserInfo, ProAuth enforces this proof. External resource servers should do the same check: validate the access token or introspection response, read cnf.x5t#S256, and compare it with the SHA-256 thumbprint of the client certificate presented on the mutually authenticated request.
This is the practical difference from a plain bearer token. Copying the token is not enough if the API also requires the matching certificate proof. It does not remove the need for short token lifetimes, audience checks, scope checks, and careful logging. It reduces the value of a token that leaks without the corresponding certificate private key.
Choose the method by threat model and operations
There is no universal winner. The right choice depends on how the client is deployed, who owns the credential lifecycle, and what the resource server needs to verify.
| Method | Proof material | ProAuth v3 preview configuration | Strongest fit | Main trade-off |
|---|---|---|---|---|
client_secret_basic | Shared client secret sent through HTTP Basic authentication | Existing secret-based confidential-client behavior, or explicit secret method where configured | Ordinary confidential clients where shared-secret operations are acceptable | Secret copying and rotation remain the central operational risk |
client_secret_jwt | JWT signed with HMAC using the shared client secret | tokenEndpointAuthMethod=client_secret_jwt; no JWKS source | Clients that need assertion-style authentication but still operate with a shared secret | The secret is still symmetric; not the ProAuth FAPI-compatible JWT option |
private_key_jwt | JWT signed with the client’s private key | tokenEndpointAuthMethod=private_key_jwt plus Client App Key Sets with usage ClientAssertionSigning | High-value confidential clients, automation, and FAPI-oriented deployments | Requires public-key registration, kid discipline, and key rotation planning |
tls_client_auth | TLS client certificate validated by PKI or trusted ingress | tokenEndpointAuthMethod=tls_client_auth plus registered subject DN or SAN metadata | Controlled server-to-server environments with certificate operations already in place | Certificate lifecycle, proxy behavior, trust boundaries, and endpoint topology |
self_signed_tls_client_auth | TLS client certificate matched to registered public key material | tokenEndpointAuthMethod=self_signed_tls_client_auth plus Client App Key Sets with usage SelfSignedTlsClientAuth | Clients that can manage their own certificate keys without relying on a broader PKI | Requires key-set registration and careful certificate rotation |
FAPI 2.0 turns some of these choices into guardrails. In ProAuth v3 preview configuration, a FAPI client must be confidential, use authorization code flow, use PAR, use S256 PKCE, authenticate with private_key_jwt, tls_client_auth, or self_signed_tls_client_auth, and use sender-constrained access tokens through DPoP or certificate binding. For mTLS clients, certificate-bound access tokens are enabled by default.
That does not mean every client should be configured as a FAPI client. It means high-value clients need a sharper answer than “we have a secret somewhere.” For backend integrations, partner APIs, regulated workloads, and payment or health data access, the stronger answer is usually asymmetric proof: a private key the client controls, a certificate the platform can validate, or both.
Review high-value clients before v3
The preview window is a good time to inventory client authentication instead of only upgrading settings mechanically.
For each high-value client, ask:
- Which OAuth endpoints does this client call: token, introspection, revocation, device authorization, or PAR?
- Is the current shared secret stored in more places than the owning team can name?
- Would
private_key_jwtgive the client a cleaner rotation model? - Is mTLS already practical in the deployment path, including ingress and resource-server validation?
- If certificate-bound access tokens are enabled, which APIs will compare
cnf.x5t#S256with the presented certificate? - During rotation, can ProAuth trust both old and new public keys or certificate keys long enough to avoid downtime?
- If the client is FAPI-bound, does it meet the full profile rather than only one authentication requirement?
The goal is not to make every integration heavier. The goal is to spend the operational cost where token replay and client impersonation would hurt.
Further reading:
- ProAuth JWT client authentication
- ProAuth mutual TLS client authentication
- ProAuth FAPI 2.0 Security Profile
- ProAuth v3 release-note page
- OpenID Connect Core client authentication
- RFC 8705: OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens
- RFC 9700: Best Current Practice for OAuth 2.0 Security