Skip to content

feat!: add Private Key JWT (private_key_jwt) client authentication - #154

Merged
kishore7snehil merged 4 commits into
mainfrom
feat/private-key-jwt-client-assertion
Aug 14, 2026
Merged

feat!: add Private Key JWT (private_key_jwt) client authentication#154
kishore7snehil merged 4 commits into
mainfrom
feat/private-key-jwt-client-assertion

Conversation

@kishore7snehil

@kishore7snehil kishore7snehil commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

📋 Changes

This PR adds Private Key JWT (private_key_jwt) client authentication to auth0-server-python, alongside the existing client secret. When a signing key is configured, the SDK authenticates to the token endpoint by signing a short-lived client assertion (RFC 7523) instead of sending a client secret. Client authentication is resolved in one place and applied uniformly across every client-authenticated call site.

✨ Features

  • New client_assertion_signing_key and client_assertion_signing_alg options on ServerClient select private_key_jwt; when neither a signing key nor a client secret is configured, token requests raise ConfigurationError before any network call
  • private_key_jwt is applied uniformly across all client-authenticated requests: authorization code exchange, refresh token, Custom Token Exchange, connection access token (Token Vault), backchannel (CIBA) initiate and grant, PAR, passkey signin, and MFA challenge and verify
  • The signing key and algorithm are validated when the client is constructed, so a malformed key or a key that does not match the algorithm fails early rather than on the first token request
  • Caller-supplied client_secret, client_assertion, and client_assertion_type are stripped from every client-authenticated request, so the SDK-controlled credentials cannot be overridden through authorization_params

🔧 API Changes

  • New ServerClient option client_assertion_signing_key: Optional[str] - a PKCS8 PEM private key that enables private_key_jwt
  • New ServerClient option client_assertion_signing_alg: Optional[str] - the assertion signing algorithm, defaulting to RS256
  • New build_client_assertion(private_key, client_id, issuer, alg) helper, validate_client_assertion_key(private_key, alg) helper, and CLIENT_ASSERTION_TYPE constant in auth0_server_python.auth_schemes.client_assertion

⚠️ Breaking Changes

  • Client-authenticated requests now require client authentication to be configured. A client with neither a client secret nor a signing key previously completed the interactive login code exchange as a public client, and now raises ConfigurationError. The MFA challenge (/mfa/challenge) previously sent client_secret: null in the body for such a client, and now raises ConfigurationError too. Configure client_secret or client_assertion_signing_key.
  • Pushed Authorization Requests now set response_type to code. This was previously missing and caused the request to be rejected. A caller that set a different response_type through authorization_params on the PAR path will have that value replaced with code.

📖 Documentation

  • Added an "Authenticating with Private Key JWT" section to the client setup in README.md, covering the signing-key configuration, where to register the public key, the algorithm requirement, the passkey challenge limitation, and that private keys must not be committed to source control

🧪 Testing

  • This change adds test coverage
  • This change has been tested on the latest version of the platform/language

Contributor Checklist

Add private_key_jwt client authentication alongside the existing client
secret. When a signing key is configured, the SDK signs a short-lived
client assertion (RFC 7523) instead of sending a client secret. Client
authentication is resolved in one place and applied uniformly across
every token-endpoint call site.

Also include the required response_type on Pushed Authorization Requests,
which was previously missing and caused the request to be rejected.
@kishore7snehil
kishore7snehil marked this pull request as ready for review August 12, 2026 13:45
@kishore7snehil
kishore7snehil requested a review from a team as a code owner August 12, 2026 13:45
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_schemes/client_assertion.py
Comment thread src/auth0_server_python/tests/test_server_client.py
Comment thread src/auth0_server_python/tests/test_server_client.py
Comment thread README.md Outdated
Address review feedback on private_key_jwt client authentication:

- Route MFA challenge and verify through the client-auth resolver so
  private_key_jwt works for MFA step-up, not only client_secret.
- Withhold the client secret from the OAuth client when a signing key is
  set, so the code exchange sends a single client authentication method.
- Validate the signing key and algorithm at construction and raise
  ConfigurationError, instead of failing on the first token request.
- Strip caller-supplied client-auth keys in the resolver so they cannot
  be injected through PAR or backchannel authorization params.
- Document ConfigurationError on the interactive login entry points and
  the Private Key JWT limitations in the README.
@kishore7snehil kishore7snehil changed the title feat: add Private Key JWT (private_key_jwt) client authentication feat!: add Private Key JWT (private_key_jwt) client authentication Aug 14, 2026
Drive the login and MFA private_key_jwt tests through complete_interactive_login
and the ServerClient-wired MFA client so a regression at the SDK call site fails
the suite, not just the helper. Add the passkey signing-key caveat to
examples/Passkeys.md, list the accepted signing algorithms in the README,
document ConfigurationError on the MFA challenge and verify methods, and chain
the client assertion validation error.
@kishore7snehil
kishore7snehil merged commit 544511e into main Aug 14, 2026
9 checks passed
@kishore7snehil
kishore7snehil deleted the feat/private-key-jwt-client-assertion branch August 14, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants