Skip to content

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's kid via Node's crypto.createPublicKey.
  • HS256 is 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_certificate present → mTLS.
  • client_assertion present → private_key_jwt / client_secret_jwt, per the alg dispatch above.
  • Otherwise → Basic Auth or a plain client_secret in 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.