Introspection
API Connectivity Manager API Owners can restrict access to their APIs with OAuth2 tokens by swapping an opaque token for claims or JWT token to be proxied to the backend service. The policy can be configured to grant access to APIs after having the tokens introspected. In addition, the claims in the token can be extracted and forwarded to the backend service.
The OAuth2 Authorization Framework [RFC-6749] grants third-party applications limited access to an HTTP service either by orchestrating an approval interaction between the resource owner and the HTTP service or granting the third-party application access on its own behalf.
OAuth2 is an authorization protocol, not an authentication protocol. As such, OAuth2 grants access to a set of resources, for example, internal APIs or user data.
The idea of roles is part of the core specification of the OAuth2 Authorization Framework. These define the essential components of an OAuth2 system:
- Resource Owner: An entity capable of granting access to a protected resource. It could be a system or an end-user.
- Client: An application making protected resource requests on behalf of the Resource Owner and with its authorization.
- Authorization Server: The server that issues access tokens to the client after successfully authenticating the resource owner and obtaining authorization. The authorization server exposes two endpoints: the Token endpoint, which is involved in a machine-to-machine interaction for issuing access tokens, and the Introspection endpoint, which is used by the Resource Server to validate client access tokens.
- Resource Server: The server protecting the user resources capable of accepting and responding to protected resource requests using access tokens. In this guide, NGINX running within the API Connectivity Manager API-Proxy is the Resource Server.
The standard method for validating access tokens with an IdP is called Token Introspection. OAuth2 Token Introspection [RFC 7662] is now a widely supported standard that describes a JSON/REST interface that a Resource Server uses to present a token to the IdP, and describes the structure of the response. It is supported by many of the leading IdP vendors and cloud providers.
NGINX can be used to validate access tokens on behalf of backend services. This has several benefits:
- Requests reach the backend services only when the client has presented a valid token
- Existing backend services can be protected with access tokens without requiring code changes
- Only the NGINX instance (not every app) needs to be registered with the IdP
- Behavior is consistent for every error condition, including missing or invalid tokens
The OAuth2 Token Introspection flow includes the following steps:

You can set up OAuth2 Introspection policy by using either the web interface or the REST API.
- In the API Connectivity Manager user interface, select Services > API Proxiesclick the … icon in the Actions column for the API proxy that you want to enable the OAuth2 Introspection policy for, select Edit Proxy.
- Under the Advanced section select Policies.
- Under the API Proxy tab, locate the OAuth2 Introspection policy and click the … icon, select Add Policy.
- Update Client Request settings.
Configuration Setting | Description |
---|---|
Specifies the token’s location in incoming user request | Specifies where the access token is supplied in the incoming user request and the key from which the access token can be extracted. The default behavior is as a Bearer token in the Authorization request header. |
- Update Introspection Request settings.
Configuration Setting | Description |
---|---|
Enter the introspection endpoint | The IdP OAuth2 Token Introspection endpoint [RFC 7662] where NGINX IdP client will send client access_token . |
Enable SNI | Enables or disables passing of the server name through TLS Server Name Indication extension (SNI), [RFC 6066] when establishing a connection with the proxied HTTPS server. |
Override the default server name | Allows overriding the server name used to verify the certificate of the proxied HTTPS server and to be passed through SNI when establishing a connection with the proxied HTTPS server. By default, the host part of the proxy_pass URL is used. |
- Update Credentials.
Configuration Setting | Description |
---|---|
Enter Client Application ID | Identifies the IdP Client making the token introspection request. |
Enter Client Secret/Password | The IdP Client secret/password. |
- Update Introspection Response settings.
Configuration Setting | Description |
---|---|
Specify the introspection response type | Whether the token introspection endpoint should respond with a JSON object or JSON Web Token (JWT). The default is application/json. |
Specify the list of claims to forward as headers to the backend | Forward claims from the token introspection response in the proxy header to the backend service. Can only be applied if the introspection response is configured to application/json. |
Enable JWT token forwarding to backend | Forward introspection token response to backend service. Can only be applied if the introspection response is configured to application/jwt. |
Specify how long introspected tokens will be cached | Specifies how long the introspected tokens will be cached. Tokens will be refreshed from the URI endpoint after the duration. Set as 0 to disable. Follows NGINX time measurement syntax. |
Specify OAuth2 Token Type Hint | A hint about the token type submitted for introspection. The protected resource can pass this parameter to help the authorization server optimize the token lookup. Values for this field are defined in [RFC6749]. |
- Enable Introspection Token Claim Verification. To add a claim to verify click + Add a claim, to add more than one claim to verify click the same symbol. To delete a claim click the trash can symbol for that claim.
Configuration Setting | Description |
---|---|
Claim | The claim name. If the claim is nested, layers of depth are indicated with periods, example: resource_access.account.roles . |
Type | The claim data type. |
Delimiter | The claim value delimiter if value is a delimited string. |
Value | The claim value to verify. |
- Enable Resolver if external DNS required.
Configuration Setting | Description |
---|---|
Time Out | By default, NGINX caches answers using the TTL value of a response. The valid parameter allows overriding it. Follows NGINX time measurement syntax. |
Valid For | Sets a timeout for name resolution. Follows NGINX time measurement syntax. |
Hostname | The DNS Hostname or IP Address. Multiple DNS Resolvers can be added for a given OAuth2 Introspection Policy. |
Listened Port | The DNS Port number |
- Update Error Handling.
Configuration Setting | Description |
---|---|
Specify authorization failed error code | The error code that needs to be used by the NGINX data plane when the backend service cannot find a token match or access is forbidden. |
Specify authorization token not provided error code | The error code that needs to be used by the NGINX data plane when the backend service when a token is not supplied. |
- Select Add.
- Select Save and Submit.
Send a POST request to add the OAuth2 Introspection policy to the API-Proxy.
Method | Endpoint |
---|---|
POST | /services/workspaces/<SERVICE_WORKSPACE_NAME>/proxies |
<strong>Note:</strong> While all request body configuration values are presented in the request body structure example below, not all configuration
values are compatible. Please see the configuration value description table for further information.
JSON request
{
"name": "{{proxyName}}",
"version": "v1",
"proxyConfig": {
"hostname": "{{environmentHostname}}",
"ingress": {
"basePath": "/api"
},
"backends": [
{
"serviceName": "backend-svc",
"serviceTargets": [
{
"hostname": "10.0.0.10"
}
]
}
],
"policies": {
"oauth2-introspection": [
{
"action": {
"introspectionEndpoint": "https://example.idp.com:8443/oauth/v2/oauth-introspect",
"enableSNI": true,
"proxyTLSName": "test.oauth.com",
"introspectionResponse": "application/json",
"cacheIntrospectionResponse": "5m",
"clientTokenSuppliedIn": "HEADER",
"clientTokenName": "Authorization",
"authzServerTokenHint": "ACCESS_TOKEN",
"forwardToken": false,
"forwardedClaimsInProxyHeader": [
"username",
"exp",
"scope"
],
"verifyClaims": [
{
"claim": "sub",
"type": "STRING",
"value": "a95117bf-1a2e-4d46-9c44-5fdee8dddd11"
},
{
"claim": "scope",
"type": "STRING",
"value": "read write email",
"delimiter": "SPACE"
},
{
"claim": "aud",
"type": "ARRAY",
"value": ["https://protected.example.net/resource"]
},
{
"claim": "resource_access.account.groups",
"type": "STRING",
"value": "default-group"
},
{
"claim": "resource_access.account.roles",
"type": "ARRAY",
"value": [
"default-roles",
"offline_access",
]
},
{
"claim": "email_verified",
"type": "BOOLEAN",
"value": true
},
{
"claim": "user-group",
"type": "INTEGER",
"value": 42
}
],
"resolver": {
"valid": "30s",
"timeout": "30s",
"servers": [
{
"hostname": "example.com"
},
{
"hostname": "10.0.0.11",
"port": 53
}
]
},
"errorReturnConditions": {
"noMatch": {
"returnCode": 403
},
"notSupplied": {
"returnCode": 401
}
}
},
"data": [
{
"clientAppID": "idp-client-app-id",
"clientSecret": "dbdaa3e1-f100-420x-bfd0-875bd8a77cd7"
}
]
}
]
}
}
}
Field | Datatype | Possible Values | Description | Required | Default value |
---|---|---|---|---|---|
introspectionEndpoint |
string | Example: "https://idp.com/introspect" |
The IdP OAuth2 Token Introspection endpoint [RFC 7662] where NGINX IdP client will send client access_token . |
True | N/A |
enableSNI |
boolean | true /false |
Enables or disables passing of the server name through TLS Server Name Indication extension (SNI), [RFC 6066] when establishing a connection with the proxied HTTPS server. | False | false |
proxyTLSName |
string | Example: test.oauth.com |
Allows overriding the server name used to verify the certificate of the proxied HTTPS server and to be passed through SNI when establishing a connection with the proxied HTTPS server. By default, the host part of the proxy_pass URL is used. |
False | Host part of introspectionRequest |
introspectionResponse |
string | One of: [ "application/json" , "application/jwt" ] |
Whether the token introspection endpoint should respond with a JSON object or JSON Web Token (JWT). | False | "application/json" |
cacheIntrospectionResponse |
string | Example: "5m" |
Specifies how long the introspected tokens will be cached. Tokens will be refreshed from the URI endpoint after the duration. Set as 0s-m-h to disable. Follows NGINX time measurement syntax. |
False | "5m" |
clientTokenSuppliedIn |
string | One of: [ "HEADER" , "QUERY" ] |
Specifies where the access token is supplied in the incoming user request. | False | "HEADER" |
clientTokenName |
string | Example: "Authorization" |
Specifies the key under which the access token can be extracted from in the incoming user request. Note: To maintain Bearer token behavior, clientTokenSuppliedIn must be set to HEADER , and clientTokenName must be set to Authorization . This is the default behavior of the Introspection Policy. |
False | "Authorization" |
authzServerTokenHint |
string | One of: [ "ACCESS_TOKEN" , "REFRESH_TOKEN" ] |
A hint about the type of the token submitted for introspection. The protected resource can pass this parameter to help the authorization server optimize the token lookup. Values for this field are defined in [RFC6749]. | False | N/A |
forwardToken |
boolean | true /false |
Forward introspection token response to backend service. Can only be applied if the introspectionResponse is set to application/jwt . |
False | true |
forwardedClaimsInProxyHeader |
array of strings | Standard claims can be found in OAuth2 Token Introspection [RFC 7662]. This is not an exhaustive list, IdPs and Resource Owners can configure their own claims. |
Forward claims from the token introspection response in the proxy header to the backend service. Can only be applied if the introspectionResponse is set to application/json . |
False | ["scope", "username", "exp"] |
verifyClaims[].claim |
string | Example: "resource_access.account.roles" |
The claim name. If the claim is nested, layers of depth are indicated with periods. | True | N/A |
verifyClaims[].type |
string | One of: [ "STRING" , "ARRAY" , "BOOLEAN" , "INTEGER" ] |
The claim data type. | True | N/A |
verifyClaims[].delimiter |
string | One of: [ "SPACE" , "COMMA" , "PERIOD" , "PLUS" , "COLON" , "SEMI-COLON" , "VERTICAL-BAR" , "FORWARD-SLASH" , "BACK-SLASH" , "HYPHEN" , "UNDERSCORE" ] |
The claim value delimiter if value is a delimited string. | Semi-Optional | N/A |
verifyClaims[].value |
- | Examples: "test-user-1" "read write email" ["default-roles","offline_access"] 42 true |
The claim value to verify. | True | N/A |
resolver.valid |
string | Example: "30s" |
By default, NGINX caches answers using the TTL value of a response. The valid parameter allows overriding it. Follows NGINX time measurement syntax. |
False | "30s" |
resolver.timeout |
string | Example: "30s" |
Sets a timeout for name resolution. Follows NGINX time measurement syntax. |
False | "30s" |
resolver.servers[].hostname |
string | Valid hostname or IP Address | The DNS Hostname. | True | N/A |
resolver.servers[].port |
int32 | Valid 32-bit integer | The DNS Port number. | False | N/A |
errorReturnConditions.noMatch |
integer | In range: 400 - 599 |
The error code that needs to be used by the NGINX data plane when the backend service cannot find a token match or access is forbidden. | False | 403 |
errorReturnConditions.notSuppplied |
integer | In range: 400 - 599 |
The error code that needs to be used by the NGINX data plane when the backend service when a token is not supplied. | False | 401 |
data.clientAppID |
string | Example: "nginx-docs-client" |
Identifies the IdP Client making the token introspection request. | True | N/A |
data.clientSecret |
string | Example: "db3e1-f100-420x-bfd0" |
The IdP Client secret/password. | True | N/A |