-
Notifications
You must be signed in to change notification settings - Fork 8
feat: add mTLS (RFC 8705) client authentication #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
cschetan77
wants to merge
30
commits into
main
Choose a base branch
from
feat/mtls-client-authentication
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
7fbe52a
feat: add use_mtls and ssl_context constructor args with validation
cschetan77 19b1484
feat: pass mTLS ssl_context to httpx and authlib clients
cschetan77 7f18573
feat: add _resolve_token_endpoint mTLS alias resolver
cschetan77 8acc86b
feat: return no body credential under mTLS in client auth resolver
cschetan77 be1fee8
feat: route all token-endpoint calls through mTLS alias resolver
cschetan77 8f786c9
feat: reject dpop_key + use_mtls in signin_with_passkey
cschetan77 3849b96
feat: warn when mTLS token lacks cnf.x5t#S256 binding
cschetan77 09bf72f
feat: thread mTLS ssl_context and alias routing through MFA verify
cschetan77 5758f63
docs: document mTLS client authentication
cschetan77 14430d6
docs: document token_endpoint_override and dpop+mTLS ConfigurationErr…
cschetan77 0398bc6
style: apply repo conventions to mTLS code and docs
cschetan77 f557dd1
refactor(tests): distribute mTLS tests next to their surfaces
cschetan77 2f26875
docs: link to Auth0 mTLS configuration docs in README
cschetan77 5bc3fec
fix: route mTLS token calls through alias resolver in MFA, passwordle…
cschetan77 4a03a5a
refactor: replace cnf.x5t#S256 UserWarning with documentation
cschetan77 e620c26
docs: document passkey challenge/register incompatibility with mTLS-o…
cschetan77 9cd5951
feat: wire ssl_context through MyAccountClient for mTLS cert-bound to…
cschetan77 e46e28b
fix: route PAR endpoint through mTLS alias when use_mtls is enabled
cschetan77 82cd04c
test: add mTLS token endpoint routing assertions for refresh, backcha…
cschetan77 66696aa
docs: document use_mtls and ssl_context in ServerClient.__init__ docs…
cschetan77 c3cf72c
feat: log warning when mTLS access token lacks cnf.x5t#S256 claim
cschetan77 16fef8e
test: add cert-bound warning tests for _warn_if_not_cert_bound
cschetan77 dee7c51
docs: update MutualTLS.md with logger warning, MFA proxy note, and pa…
cschetan77 84148c6
docs: fix stale token_endpoint_override reference in flow-map
cschetan77 7e0713a
test: add mTLS routing, credential, and ssl_context assertions for pa…
cschetan77 38d5e93
test: add body credential assertions and authlib constructor verifica…
cschetan77 0bb9481
style: fix repo convention violations flagged in PR review
cschetan77 092472d
refactor: remove redundant algorithms arg from unverified jwt.decode …
cschetan77 f80df61
style: fix semicolon clause-splice in passwordless verify error message
cschetan77 ae23056
docs: fix passkeys section and remove what-comment in server_client
cschetan77 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| # Mutual TLS (mTLS) Client Authentication | ||
|
|
||
| Authenticate to Auth0 with a TLS client certificate instead of a client secret (RFC 8705). The certificate is presented during the TLS handshake. No credential travels in the request body. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Auth0 **Enterprise** tenant with the **Highly Regulated Identity** add-on | ||
| - A `self_managed_certs` **custom domain** configured on the tenant | ||
| - **Allow mTLS Endpoint Aliases** enabled on the tenant (Dashboard → Settings → Advanced) | ||
| - Client application's authentication method set to **mTLS** in Dashboard → Applications → Settings → Credentials | ||
|
|
||
| ## Generating a client certificate (development) | ||
|
|
||
| ```bash | ||
| # Self-signed CA + client cert (development only - use your PKI in production) | ||
| openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 365 -nodes \ | ||
| -subj "/CN=dev-ca" | ||
| openssl req -newkey rsa:2048 -keyout client.key -out client.csr -nodes \ | ||
| -subj "/CN=my-app-client" | ||
| openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ | ||
| -out client.crt -days 365 | ||
| ``` | ||
|
|
||
| ## Wiring into `ServerClient` | ||
|
|
||
| ```python | ||
| import ssl | ||
| from auth0_server_python.auth_server.server_client import ServerClient | ||
|
|
||
| ssl_context = ssl.create_default_context() # trusts system/public CAs for the server side | ||
| ssl_context.load_cert_chain("client.crt", "client.key") # attaches the client identity | ||
|
|
||
| auth0 = ServerClient( | ||
| domain="login.example.com", # self_managed_certs custom domain | ||
| client_id="<AUTH0_CLIENT_ID>", | ||
| use_mtls=True, | ||
| ssl_context=ssl_context, | ||
| secret="<AUTH0_SECRET>", | ||
| authorization_params={ | ||
| "audience": "<API_IDENTIFIER>", | ||
| "scope": "openid profile email offline_access", | ||
| }, | ||
| ) | ||
| ``` | ||
|
|
||
| The SDK passes `ssl_context` as `verify=ssl_context` to every `httpx.AsyncClient` it constructs, including the authlib client used for the authorization-code exchange. You never call `load_cert_chain` inside the SDK - the caller owns the TLS material. | ||
|
|
||
| ## Mutual exclusion | ||
|
|
||
| `use_mtls=True` cannot be combined with: | ||
|
|
||
| | Parameter | Reason | | ||
| |-----------|--------| | ||
| | `client_secret` | One client-auth method only - Auth0 rejects requests carrying both. | | ||
| | `client_assertion_signing_key` | Same - one method only. | | ||
| | `dpop_key` (per-call on `signin_with_passkey` / `mfa.verify`) | DPoP binds to its own key (`cnf.jkt`) and suppresses `cnf.x5t#S256`. Combining them silently defeats mTLS token binding. | | ||
|
|
||
| All three raise `ConfigurationError` immediately (constructor for the first two, at the call site for DPoP). | ||
|
cschetan77 marked this conversation as resolved.
|
||
|
|
||
| ## Token sender-constraining | ||
|
|
||
| When the target API has **Token Sender-Constraining (mTLS)** enabled, issued access tokens carry a `cnf.x5t#S256` claim binding the token to the certificate thumbprint. | ||
|
|
||
| The SDK logs a warning at the `auth0_server_python.auth_server.server_client` logger whenever an access token returned by the authorization-code or refresh-token flow does not contain `cnf.x5t#S256`. If you see that warning, enable **Token Sender-Constraining (mTLS)** on the API resource server in the Auth0 Dashboard. | ||
|
|
||
| ## MFA under mTLS | ||
|
|
||
| The client certificate is presented on all MFA API calls. The token-endpoint call inside `mfa.verify` is routed through the mTLS alias automatically. Challenge and enrollment calls (`/mfa/challenge`, `/mfa/associate`) go to the standard host. The certificate is still included in the TLS handshake, but whether it reaches the Auth0 backend depends on the proxy configuration. | ||
|
|
||
| ```python | ||
| await auth0.mfa.verify( | ||
| {"mfa_token": encrypted_token, "otp": "123456"}, | ||
| ) | ||
| ``` | ||
|
|
||
| ## Passkeys under mTLS | ||
|
|
||
| The client certificate is presented on all passkey calls. The token-exchange step (`signin_with_passkey`) calls the token endpoint, which is served on the mTLS alias and routed correctly. | ||
|
|
||
| Challenge and enrollment calls (`/passkey/challenge`, `/passkey/register`) go to the standard host - they are not listed in `mtls_endpoint_aliases`. The certificate is still included in the TLS handshake, but whether it reaches the Auth0 backend depends on the proxy configuration - the same behaviour as `/mfa/challenge`. | ||
|
|
||
| ## Passwordless under mTLS | ||
|
|
||
| By default, Auth0 does not require client authentication on `/passwordless/start`. If the `enforce_client_authentication_on_passwordless_start` tenant flag is enabled on your tenant, the call will fail because `/passwordless/start` does not support certificate-based client authentication. | ||
|
|
||
| The verify step (`passwordless_client.verify`) calls the token endpoint, which is served on the mTLS alias and routed correctly. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.