OAuth2 Client Authentication¶
Beyond a shared client_secret, the token endpoint (packages/api/src/routes/v1/token.ts) supports
two additional client authentication methods per RFC, dispatched automatically based on what the
token request actually contains.
private_key_jwt / client_secret_jwt (RFC 7523)¶
Send a client_assertion JWT (with client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer)
instead of a secret. The emulator dispatches on the JWT header's alg:
- Asymmetric algorithms —
RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512— are verified against the client's registered JWKS, looked up by the JWT header'skidvia Node'scrypto.createPublicKey. HS256is verified against the client's own shared secret instead.
This split is a deliberate anti-alg-confusion measure: the asymmetric-algorithm allow-list is
explicit, so a client can't submit an HS256-signed assertion and have it accidentally verified as
if it were a JWKS-backed asymmetric one (or vice versa).
mTLS (tls_client_auth, RFC 8705)¶
Since this emulator has no real TLS-terminating origin in front of it, mTLS is simulated at the API
level: the client sends its certificate as a PEM string in the token request body's
client_certificate field, rather than via an actual mutual-TLS handshake. The emulator verifies it
using Node's crypto.X509Certificate (checkIssued() + .verify()) against the partner-registered
CA and subject DN trust anchors for that client.
POST /:environmentId/as/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=...
&client_certificate=-----BEGIN CERTIFICATE-----...
What determines which method is used¶
The token endpoint inspects the request body itself, not a separate flag:
client_certificatepresent → mTLS.client_assertionpresent →private_key_jwt/client_secret_jwt, per thealgdispatch above.- Otherwise → Basic Auth or a plain
client_secretin the body.
PingFederate-backed environments
client_assertion and client_certificate authentication are not yet supported for
environments whose authProvider is pingfederate rather than emulated — the token endpoint
returns an explicit error for either method against such an environment rather than silently
falling back to a weaker check.
Registering clients in self-service-darkedges¶
The self-service-darkedges partner portal lets an organization register OAuth clients under an
approved application, supporting all three methods above, including rotating a private_key_jwt
keypair and adding mTLS trust anchors after creation. Client private keys for private_key_jwt are
generated in the browser (crypto.subtle.generateKey) — only the derived public JWK is ever sent
to the backend.