Protect APIs using PingOne token introspection
This example sets up OAuth 2.0, using the standard introspection endpoint, where PingOne acts as the authorization server (AS) and PingGateway acts as the resource server (RS).
About the example
In this example PingOne plays the role of OAuth 2.0 AS.
The AS issues access tokens to OAuth 2.0 client applications. This example has you configure an OAuth 2.0 client to get an access token.
PingGateway plays the role of RS. As RS, it receives access tokens in requests from the OAuth 2.0 client application. It sends the tokens in introspection requests to the AS. The example ends by showing the introspection response, the content of the access token you got.
An RS can use the access token content to decide whether to grant the OAuth 2.0 client the access it requests. For example, PingGateway can use this to protect APIs.
For PingOne in this example, you configure an OAuth 2.0 client application to get the access token. You configure a resource profile for PingGateway that defines the scopes it enforces as an RS. The OAuth 2.0 client allows the RS scopes and access token requests include one or more of them.
Before you begin
If you haven’t already done so:
-
Install PingGateway with HTTPS listening on port 8443 and routes for static resources.
-
Create a PingOne environment.
Learn more in the PingGateway and PingOne examples.
You don’t need the sample application or test user for this example.
Tasks
Complete these tasks to prepare your environment for this example:
PingOne: Configure an RS profile
-
In the PingOne admin console, go to Applications > Resources and create a new resource profile using these hints and accepting the defaults for other fields:
- Resource Name
-
PingGateway - Audience
-
https://ig.example.com:8443 - Scopes
-
Add Scope Name:
resource:access
-
Record the environment ID, resource ID, and resource secret for use in the token introspection request.
You use these to configure PingGateway.
You’ve successfully created the PingGateway resource profile.
PingOne: Configure an OAuth 2.0 client profile
-
In the PingOne admin console, go to Applications > Applications and create a new OIDC Web App profile using these hints and accepting the defaults for other fields:
- Application Name
-
oauth2client - Configuration > OIDC Settings > Grant Type
-
Select
Client Credentials - Resources > Scopes
-
Select
resource:access
-
Record the environment ID, client ID, and client secret for use in the access token request.
-
Enable the client profile.
You’ve successfully created an OAuth 2.0 client application profile.
PingGateway: Add resource secret
PingGateway reads the secret for the resource profile from its environment.
-
Add the base64-encoded the resource secret to the PingGateway environment:
$ export PINGONE_RESOURCE_SECRET=$(echo -n 'resource-secret' | base64) -
Restart PingGateway to load the secret.
You’ve successfully loaded the secret from the PingGateway environment.
PingGateway: Add an RS route
Add the following route to PingGateway and correct the "properties" settings:
- Linux
-
$HOME/.openig/config/routes/introspect-p1.json - Windows
-
%appdata%\OpenIG\config\routes\introspect-p1.json
{
"name": "introspect-p1",
"condition": "${find(request.uri.path, '^/p1-introspect')}",
"properties": {
"pingOneResourceId": "<resourceId>",
"pingOneIntrospectUrl": "https://auth.pingone.com/<envId>/as/introspect"
},
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "OAuth2ResourceServerFilter",
"config": {
"scopes": [
"resource:access"
],
"requireHttps": false,
"accessTokenResolver": {
"type": "TokenIntrospectionAccessTokenResolver",
"config": {
"endpoint": "&{pingOneIntrospectUrl}",
"providerHandler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "ClientSecretBasicAuthenticationFilter",
"config": {
"clientId": "&{pingOneResourceId}",
"clientSecretId": "pingone.resource.secret",
"secretsProvider": {
"type": "SystemAndEnvSecretStore"
}
}
}
],
"handler": "ClientHandler"
}
}
}
}
}
}
],
"handler": {
"type": "StaticResponseHandler",
"config": {
"status": 200,
"headers": {
"Content-Type": [
"text/html; charset=UTF-8"
]
},
"entity": "<html><body><p>Decoded access_token: <code>${contexts.oauth2.accessToken.info}</code></p></body></html>"
}
}
}
}
}
Source: introspect-p1.json
The route:
-
Serves requests to
/p1-introspect. -
Connects to PingOne using the PingGateway resource profile credentials.
-
Requests introspection of the access token provided in the
Authorizationheader from the client. -
Displays the access token content in an HTML page.
You’ve successfully configured PingGateway to introspect an access token.
Validation
-
Get an access token.
How you get the token doesn’t matter as long as it has the scope or scopes the RS requires.
This example uses a client credentials grant with the OAuth 2.0 client profile you created to get an access token with the
resource:accessscope. Replace{envId},{clientId}, and{clientSecret}with the values you copied from the OAuth 2.0 client profile:$ curl \ "https://auth.pingone.com/{envId}/as/token" \ --request POST \ --header "Content-Type: application/x-www-form-urlencoded" \ --user "{clientId}:{clientSecret}" \ --data "grant_type=client_credentials" \ --data "scope=resource:access"PingOne responds with an access token:
{ "access_token" : "{access-token}", "token_type" : "Bearer", "expires_in" : 3600, "scope" : "resource:access" } -
Curl the PingGateway route to introspect the access token.
Replace
{access-token}in the following command with the token from PingOne:$ export ACCESS_TOKEN="{access-token}" $ curl --insecure --header "Authorization: Bearer ${ACCESS_TOKEN}" https://ig.example.com:8443/p1-introspectThe route displays the decoded access token in an HTML response, with lines wrapped here for readability:
<html><body><p>Decoded access_token: <code>{ active=true, scope=resource:access, client_id={clientId}, token_type=Bearer, exp={timestamp}, iat={timestamp}, aud=[https://ig.example.com:8443], iss=https://auth.pingone.com/{envId}/as, jti=..., env={envId}, org=..., p1.rid=... }</code></p></body></html>
You’ve successfully demonstrated token introspection with PingGateway as the RS and PingOne as the AS.