Client credentials grant with PingAM
This example shows how a client service accesses an OAuth 2.0-protected resource by using its OAuth 2.0 client credentials.
- 
Set up the AM as an Authorization Server:
- 
Register a PingGateway agent with the following values, as described in Register a PingGateway agent in AM:
- 
Agent ID:
ig_agent - 
Password:
password - 
Token Introspection:
Realm OnlyUse secure passwords in a production environment. Consider using a password manager to generate secure passwords.  
 - 
 - 
Create an OAuth 2.0 Authorization Server:
- 
Select Services > Add a Service > OAuth2 Provider.
 - 
Add a service with the default values.
 
 - 
 - 
Create an OAuth 2.0 client to request access tokens, using client credentials for authentication:
- 
Select Applications > OAuth 2.0 > Clients, and add a client with the following values:
- 
Client ID :
client-service - 
Client secret :
password - 
Scope(s) :
client-scope 
 - 
 - 
(Optional) On the Core tab, switch to using a client secret associated with a secret label by setting a Secret Label Identifier and mapping the label to a secret.
To learn more, read Create a client profile and Map and rotate secrets in the AM documentation.
 - 
On the Advanced tab, select the following value:
- 
Grant Types :
Client Credentials 
 - 
 
 - 
 
 - 
 - 
Set up PingGateway:
- 
Set up PingGateway for HTTPS, as described in Configure PingGateway for TLS (server-side).
 - 
Set an environment variable for the PingGateway agent password, and then restart PingGateway:
$ export AGENT_SECRET_ID='cGFzc3dvcmQ='The password is retrieved by a SystemAndEnvSecretStore, and must be base64-encoded.
 - 
Add the following route to PingGateway:
- Linux
 - 
$HOME/.openig/config/routes/oauth2-protected-resource.json - Windows
 - 
%appdata%\OpenIG\config\routes\oauth2-protected-resource.json 
{ "name": "oauth2-protected-resource", "condition": "${find(request.uri.path, '^/oauth2-protected-resource')}", "heap": [ { "name": "SystemAndEnvSecretStore-1", "type": "SystemAndEnvSecretStore" }, { "name": "AmService-1", "type": "AmService", "config": { "agent": { "username": "ig_agent", "passwordSecretId": "agent.secret.id" }, "secretsProvider": "SystemAndEnvSecretStore-1", "url": "http://am.example.com:8088/openam/" } } ], "handler": { "type": "Chain", "config": { "filters": [ { "name": "OAuth2ResourceServerFilter-1", "type": "OAuth2ResourceServerFilter", "config": { "scopes": [ "client-scope" ], "requireHttps": false, "accessTokenResolver": { "name": "TokenIntrospectionAccessTokenResolver-1", "type": "TokenIntrospectionAccessTokenResolver", "config": { "amService": "AmService-1", "providerHandler": { "type": "Chain", "config": { "filters": [ { "type": "HttpBasicAuthenticationClientFilter", "config": { "username": "ig_agent", "passwordSecretId": "agent.secret.id", "secretsProvider": "SystemAndEnvSecretStore-1" } } ], "handler": "ForgeRockClientHandler" } } } } } } ], "handler": { "type": "StaticResponseHandler", "config": { "status": 200, "headers": { "Content-Type": [ "text/html; charset=UTF-8" ] }, "entity": "<html><body><h2>Access Granted</h2></body></html>" } } } } }Source: oauth2-protected-resource.json
Notice the following features of the route:
- 
The route matches requests to
/oauth2-protected-resource. - 
The
OAuth2ResourceServerFilterexpects an OAuth 2.0 access token in the header of the incoming request, with the scopeclient-scope. - 
The filter uses a TokenIntrospectionAccessTokenResolver to resolve the access token. The introspect endpoint is protected with HTTP Basic Authentication, and the
providerHandleruses an HttpBasicAuthenticationClientFilter to provide the resource server credentials. - 
For convenience in this test,
"requireHttps"is false. In production environments, set it to true. - 
After the filter successfully validates the access token, it creates a new context from the Authorization Server response, containing information about the access token.
 - 
The StaticResponseHandler returns a message that access is granted.
 
 - 
Add the following route to PingGateway:
- Linux
 - 
$HOME/.openig/config/routes/client-credentials.json - Windows
 - 
%appdata%\OpenIG\config\routes\client-credentials.json 
{ "name": "client-credentials", "baseURI": "http://ig.example.com:8080", "condition" : "${find(request.uri.path, '^/client-credentials')}", "heap" : [ { "name" : "clientSecretAccessTokenExchangeHandler", "type" : "Chain", "capture" : "all", "config" : { "filters" : [ { "type" : "ClientSecretBasicAuthenticationFilter", "config" : { "clientId" : "client-service", "clientSecretId" : "client.secret.id", "secretsProvider" : { "type" : "Base64EncodedSecretStore", "config" : { "secrets" : { "client.secret.id" : "cGFzc3dvcmQ=" } } } } } ], "handler" : "ForgeRockClientHandler" } }, { "name" : "oauth2EnabledClientHandler", "type" : "Chain", "capture" : "all", "config" : { "filters" : [ { "type" : "ClientCredentialsOAuth2ClientFilter", "config" : { "tokenEndpoint" : "http://am.example.com:8088/openam/oauth2/access_token", "endpointHandler": "clientSecretAccessTokenExchangeHandler", "scopes" : [ "client-scope" ] } } ], "handler" : "ForgeRockClientHandler" } } ], "handler" : { "type" : "ScriptableHandler", "config" : { "type" : "application/x-groovy", "clientHandler" : "oauth2EnabledClientHandler", "source" : [ "request.uri.path = '/oauth2-protected-resource'", "return http.send(context, request);" ] } } }Source: client-credentials.json
Note the following features of the route:
- 
The route matches requests to
/client-credentials. - 
The ScriptableHandler rewrites the request to target the
/oauth2-protected-resourceendpoint and then calls the HTTP client that has been redefined to use the oauth2EnabledClientHandler. - 
The oauth2EnabledClientHandler calls the ClientCredentialsOAuth2ClientFilter to obtain an access token from AM.
 - 
The ClientCredentialsOAuth2ClientFilter calls the clientSecretAccessTokenExchangeHandler to exchange tokens on the authorization endpoint.
 - 
The clientSecretAccessTokenExchangeHandler calls a ClientSecretBasicAuthenticationFilter to authenticate the client through the HTTP basic access authentication scheme, and a ForgeRockClientHandler to propagate the request.
 - 
The route
oauth2-protected-resource.jsonuses the AM introspection endpoint to resolve the access token and display its contents. 
 
 - 
 - 
Test the setup:
- 
In your browser’s privacy or incognito mode, go to to https://ig.example.com:8443/client-credentials.
 - 
If you see warnings that the site isn’t secure, respond to the warnings to access the site.
A message shows that access is granted.
 
 -