Client App Key Sets
ProAuth v3 stores client-owned public keys in first-class ClientAppKeySet records. A key set belongs to one client application and can be used by one or more security features through its usage flags.
Use key sets for public keys that ProAuth must trust when it validates something produced by the client, or for public encryption keys that ProAuth uses when it encrypts tokens for the client. Do not store client private keys in public key sets.
When To Configure A Key Set
| Feature | Configure a ClientAppKeySet? | Required usage |
|---|---|---|
private_key_jwt client authentication | Yes | ClientAssertionSigning |
| JWT-secured authorization requests (JAR) | Yes | RequestObjectSigning |
self_signed_tls_client_auth | Yes | SelfSignedTlsClientAuth |
| Access token, ID token, UserInfo, or introspection response encryption | Yes | TokenEncryption |
tls_client_auth with CA or ingress validated certificates | No | Configure subject DN or SAN metadata on ClientAppAuthenticationConfiguration |
| Certificate-bound access tokens | No additional key set | ProAuth binds the access token to the certificate presented at the token endpoint |
| DPoP-bound access tokens | No static key set | The DPoP public key is sent in each DPoP proof and bound to the issued token |
INFO
If the same public JWKS is intentionally used for more than one feature, use one key set with multiple usage flags. If different teams, deployments, rotation schedules, or trust boundaries own the keys, create separate key sets per usage.
Key Set Fields
Use the v2 Management API resource api/management/v2/ClientAppKeySet or the AdminApp key-set section of a client application.
| Field | Description |
|---|---|
clientAppId | Client application that owns the key set. |
name | Human-readable name. Use names that identify the owner and purpose, for example portal-prod private_key_jwt. |
description | Optional operational notes, such as certificate serial numbers or rotation ticket references. |
sourceType | One of InlinePublicJwks, RemoteJwksUri, or InlineProtectedJwks. |
usage | One or more key usages: ClientAssertionSigning, RequestObjectSigning, SelfSignedTlsClientAuth, TokenEncryption. |
status | Lifecycle state: Next, Active, Retiring, Retired, or Revoked. |
jwksUri | HTTPS URI for remote public JWKS sources. |
jwksJson | Inline public JWKS for signing, self-signed TLS client authentication, or asymmetric encryption. |
protectedJwksJson | Protected inline JWKS for token encryption keys that must be protected at rest, including symmetric oct keys. |
validFrom / validTo | Optional operational validity window. Runtime only uses key sets inside this window. |
lastValidatedOn / lastValidationError | Diagnostic validation metadata. |
Runtime key resolution uses only key sets with status Active or Retiring and a currently valid time window. Next is useful for staging future configuration, but it is not used to validate signatures or encrypt tokens until it is changed to Active.
When one key set intentionally serves multiple features, provide a comma-separated usage value, for example ClientAssertionSigning, RequestObjectSigning.
Source Types
InlinePublicJwks
Use InlinePublicJwks when the public key material should be stored directly with the client configuration.
{
"name": "Portal private_key_jwt signing keys",
"clientAppId": "10000000-0000-4000-8000-000000000010",
"sourceType": "InlinePublicJwks",
"usage": "ClientAssertionSigning",
"status": "Active",
"jwksJson": "{\"keys\":[{\"kty\":\"RSA\",\"kid\":\"portal-signing-2026-01\",\"use\":\"sig\",\"alg\":\"RS256\",\"n\":\"...\",\"e\":\"AQAB\"}]}"
}Inline public JWKS may contain public RSA or EC keys. Signing and self_signed_tls_client_auth keys must be public asymmetric keys. Do not include private JWK members such as d, p, q, dp, dq, or qi.
RemoteJwksUri
Use RemoteJwksUri when the client publishes keys at a stable HTTPS endpoint.
{
"name": "Portal remote signing keys",
"clientAppId": "10000000-0000-4000-8000-000000000010",
"sourceType": "RemoteJwksUri",
"usage": "ClientAssertionSigning",
"status": "Active",
"jwksUri": "https://portal.example.com/.well-known/jwks.json"
}Remote JWKS fetching is HTTPS-only, does not follow redirects, applies a short timeout and response-size limit, and rejects loopback, private, link-local, multicast, documentation, and reserved network targets. Publish old and new keys together during rotation so ProAuth can validate both kid values.
InlineProtectedJwks
Use InlineProtectedJwks only for token encryption keys that must be protected at rest.
{
"name": "Resource server introspection response encryption key",
"clientAppId": "10000000-0000-4000-8000-000000000020",
"sourceType": "InlineProtectedJwks",
"usage": "TokenEncryption",
"status": "Active",
"protectedJwksJson": "{\"keys\":[{\"kty\":\"oct\",\"kid\":\"rs-enc-2026-01\",\"use\":\"enc\",\"alg\":\"A256KW\",\"k\":\"...\"}]}"
}Protected JWKS key sets are valid only with TokenEncryption. Symmetric JWE key wrapping algorithms such as A128KW and A256KW require this source type.
Rotation Guidance
Register more than one key during rotation. This avoids downtime for clients, distributed deployments, and cached remote JWKS documents.
Recommended rotation process for signing keys:
- Create the new key set as
Next, or publish the new key in the existing remote JWKS while the key set remainsActive. - Change the new key set to
Activebefore clients start signing with the newkid. - Keep the old key set
ActiveorRetiringuntil all old assertions, request objects, certificates, or encrypted responses can no longer be used. - Change the old key set to
Retired. - Use
Revokedonly when the key must stop being trusted immediately.
For remote JWKS, prefer one stable URI per deployed application or resource server. During rotation, publish both keys at that URI. For inline JWKS, either add both keys to one key set or create a second key set with the same usage. Separate key sets are easier to audit when the old and new keys have different validity windows or owners.
For CLI-style or installed software clients, do not register every end-user installation unless the installation has a stable identity and lifecycle you can administer. For broad CLI distributions, prefer DPoP when the proof key is generated per token flow, or use a small number of managed confidential-client deployments with registered key sets for private_key_jwt, JAR, or token encryption.
YAML Import
In ProAuth CLI YAML imports, key sets are owned children of ClientApp. Use clientAppKeySets for long-lived configuration files. The shorter keySets alias is also accepted.
apiVersion: management.proauth.net/v2
kind: ClientApp
metadata:
id: "{{guid:portal-client}}"
spec:
subscriptionId: "{{guid:subscription}}"
name: "Portal"
enabled: true
isPublic: false
allowUserLogin: true
clientAppKeySets:
- id: "{{guid:portal-client-assertion-key}}"
name: "Portal private_key_jwt signing keys"
sourceType: InlinePublicJwks
usage: ClientAssertionSigning
status: Active
jwksJson: '{"keys":[{"kty":"RSA","kid":"portal-signing-2026-01","use":"sig","alg":"RS256","n":"...","e":"AQAB"}]}'For client authentication settings, create a separate ClientAppAuthenticationConfiguration resource and keep key material in clientAppKeySets:
apiVersion: management.proauth.net/v2
kind: ClientAppAuthenticationConfiguration
metadata:
id: "{{guid:portal-client}}"
spec:
tokenEndpointAuthMethod: private_key_jwtThe importer creates missing key sets and updates existing key sets by id. Omitting clientAppKeySets leaves existing key sets unchanged.