JWK-based proof-of-possession
To implement JWK-based proof-of-possession, the client includes a JWK when making a request to the authorization server for an access token as per Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs) spec. The JWK consists of the public key of a key pair generated by the client.
When the client presents the access token to a resource server, the resource server can cryptographically confirm proof-of-possession of the token by using the associated JWK to form a challenge-response interaction with the client.
JWK-based proof-of-possession flow explained
-
The client requests an access token using any of the OAuth 2.0 grant flows, and includes a JWK in the request.
This JWK consists of the public key of a key pair generated by the client.
-
The authorization server returns the access token to the client:
-
If the authorization server is configured for server-side OAuth 2.0, it stores the JWK with the access token in the CTS token store and provides the client with the access token ID.
-
If the authorization server is configured for client-side OAuth 2.0, the access token is a JWT that contains the JWK embedded in it.
-
-
The client requests access to the protected resources from the resource server.
-
The resource server recovers the JWK associated with the access token:
-
If the resource server receives an access token ID (server-side OAuth 2.0), it introspects the access token ID to recover the JWK from the authorization’s server CTS token store.
-
If the resource server receives an access token JWT (client-side OAuth 2.0), it already has access to the JWK, which is embedded.
-
-
The resource server creates a challenge using the JWK. Usually, these challenges are messages or nonces that have been encrypted with the JWK.
-
The resource server sends the challenge to the client.
-
The client solves the challenge using the private key of its key pair.
-
The client sends the response to the challenge to the resource server.
-
The resource server validates the response and allows access to the resource.
Obtain an access token using JWK-based proof-of-possession
-
Generate a JSON web key pair for the OAuth 2.0 client.
AM supports both RSA and elliptic curve (EC) key types. For testing purposes, you can use an online JSON web key generator, such as mkjwk, to generate a key pair in JWK format.
You must sure store the full key pair, including the private key, in a secure location that is accessible by your OAuth 2.0 client.
Your OAuth 2.0 client should never reveal the private key.
-
Represent the public key of the key pair in JWK format.
For example:
{ "jwk":{ "alg":"RS256", "e":"AQAB", "n":"xea7Tb7rbQ4ZrHNKrg...QFXtJ-didSTtXWCWU1Qrcj0hnDjvkuUFWoSQ_7Q", "kty":"RSA", "use":"enc", "kid":"myPublicJSONWebKey" } }
The jwe
andjku
formats are not supported; the public key must be represented injwk
format. -
Base64-encode the JWK.
For example:
ew0KICAgICJKV0siOiB7DQogICAgICAgICJhbGciOiAiUlMyNTYiLA0KICAgICAgICAiZSI6IC JBUUFCIiwNDQogICAgICAgICJraWQiOiAibXlQdWJsaWNKU09OV2ViS2V5Ig0KICAgIH0NCn0=
-
The client includes the base64-encoded JWK as the value of the
cnf_key
parameter in the request to the authorization server for an access token.For example, in the Client credentials grant, the client makes a POST call to the authorization server’s token endpoint specifying, at least, the following parameters:
-
grant_type=client_credentials
-
cnf_key=your-base64-encoded-JWK
Confidential clients can authenticate to the OAuth 2.0 endpoints in several ways. This example uses the following form parameters:
-
client_id=your-client-id
-
client_secret=your-client-secret
For more information, see OAuth 2.0 client authentication.
For example:
$ curl \ --request POST \ --data "grant_type=client_credentials"\ --data "client_id=myClient" \ --data "client_secret=forgerock" \ --data "cnf_key=ew0KICAgICJKV0siOiB7DQogICAgICAgICJhb GciOiAiUlMyNTYiLA0KICAgICAgICAiZSI6IC JBUUFCIiwNDQogICAgICAgICJraWQiOiAibXl QdWJsaWNKU09OV2ViS2V5Ig0KICAgIH0NCn0=" \ "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"
For more information about how to use the different OAuth 2.0 grant flows, see OAuth 2.0 grant flows.
The authorization server returns the access token:
-
If the authorization server is configured to use server-side OAuth 2.0 tokens, the response will include an access token ID in the
access_token
property, which identifies the access token data stored on the server. For example:
{ "access_token":"f08f1fcf-3ecb-4120-820d-fb71e3f51c04", "scope":"profile", "token_type":"Bearer", "expires_in":3599 }
-
If the authorization server is configured to use client-side OAuth 2.0 tokens, the response will be a JSON web token in the
access_token
, which has the JWK embedded within. The following example has shortened the access token for display purposes:
{ "access_token": "eyJ0eXAiOiJKV1QiLCHi51zbE3t…zc2NjI3NDgsInNjb3zUOCVKCX0Se0", "scope": "profile", "token_type": "Bearer", "expires_in": 3599 }
-
-
The client now requests access to the protected resources from the resource server.
If server-side OAuth 2.0 tokens are enabled, the resource server can make a POST request to the
/oauth2/introspect
endpoint to acquire the public key. The public key from the original JWK is returned in thecnf
element:$ curl \ --request POST \ --header "Authorization: Basic bXlDbGllbnQ6Zm9yZ2Vyb2Nr" \ --data "token=f08f1fcf-3ecb-4120-820d-fb71e3f51c04" \ "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect" { "active": true, "scope": "profile", "client_id": "myClient", "user_id": "myClient", "username":"myClient", "token_type": "access_token", "exp": 1477666348, "sub": "(age!myClient)", "subname": "myClient", "iss": "https://openam.example.com:8443/openam/oauth2/realms/root", "cnf": { "jwk": { "alg": "RS256", "e": "AQAB", "n": "xea7Tb7rbQ4ZrHNKrg…QFXtJ-didSTtXWCWU1Qrcj0hnDjvkuUFWoSQ_7Q", "kty": "RSA", "use": "enc", "kid": "myPublicJSONWebKey" }, "auth_level": 0 } }
-
The resource server should now use the public key to cryptographically confirm proof-of-possession of the token by the presenter; for example, with a challenge-response interaction.
Successful completion of the challenge-response means that the client must possess the private key that matches the public key presented in the original request, and access to resources can be granted.