OpenID Connect with Curity

Phantom Token Integration

This guide describes how to integrate Kong Gateway Enterprise and the Curity Identity Server using the Kong OpenID Connect plugin.

This guide focuses on configuring the plugin for introspection, and especially as it relates to the introspection using the Phantom Token pattern. Some tweaks are made so that a phantom token is provided in the introspection response and then passed on to the upstream API.

Configuring the Curity Identity Server to provide a Phantom Token in the introspection response is outlined in more detail in this Introspection and Phantom Tokens article.

Prerequisites

Configure Kong

The Kong OpenID Connect plugin is configured to introspect an incoming opaque access token and in return receive a JWT in the introspection response from the Curity Identity Server. The plugin is enabled for a service or a route.

As part of the introspection, the OpenID Connect plugin also has the ability to validate that required scopes are available in the introspected token. Access to the requested API are denied if the correct scopes are missing.

If access is granted, the JWT from the introspection response is added to a header and forwarded to the upstream API where it can be consumed.

Create a service

Create a service that can be used to test the integration.

  1. curl -i -X POST http://localhost:8001/services/ \
  2. --data name="httpbin" \
  3. --data protocol="http" \
  4. --data url="http://httpbin.org"

Create a route

Add a route to the service.

  1. curl -i -X POST http://localhost:8001/services/httpbin/routes \
  2. --data "paths[]=/httpbin"

Configure the plugin

The Kong OpenID Connect plugin is enabled for the previously created service. In the example below, the openid scope is required in order for access to be granted. As noted by the config.upstream_headers_claims configuration, the plugin looks for the JWT (the phantom token) claim in the introspection response. The config.upstream_headers_names configuration extracts the JWT from the introspection response and adds it to a phantom_token header in the call to the upstream API.

  1. curl -X POST http://localhost:8001/services/httpbin/plugins \
  2. --data name="openid-connect" \
  3. --data config.issuer="https://idsvr.example.com/oauth/v2/oauth-anonymous" \
  4. --data config.client_id="gateway-client" \
  5. --data config.client_secret="Password1" \
  6. --data config.scopes_required="openid" \
  7. --data config.hide_credentials="true" \
  8. --data config.upstream_access_token_header= \
  9. --data config.upstream_headers_claims="phantom_token" \
  10. --data config.upstream_headers_names="phantom_token" \
  11. --data config.auth_methods="introspection"
ParameterDescriptionExampleRequired for integration
config.issuerUsed for discovery. Kong appends /.well-known/openid-configuration. Should be set to the realm or iss if no discovery endpoint is available.https://idsvr.example.com/oauth/v2/oauth-anonymousYes
config.client_idThe ID of a client with the introspection capabilitygateway-clientYes
config.client_secretSecret of the client used for introspectionPassword1Yes
config.scopes_requiredOptional scopes required in introspection result for coarse grained authorization. By default the plugin looks for the scopes in the scopes claim in the introspection result. This could be overridden with the config.scopes_claim configuration.openid email records_readNo
config.hide_credentialsBoolean value. This will prevent the incoming Access Token from being forwarded to the upstream API.trueNo
config.upstream_access_token_headerIn order to prevent the plugin from adding the Access Token back in the upstream request, actively set this value to nothing (aka, nil) by setting config.upstream_access_token_header= as in the example above . This configuration works in conjunction with config.hide_credentials to prevent the incoming Access Token from being passed to the upstream API.authorization:bearerNo
config.upstream_headers_claimsContains claim that holds Phantom Token in the introspection result.phantom_tokenYes
config.upstream_headers_namesContains upstream header name that will hold the Phantom Token from the introspection result.phantom_tokenYes
config.auth_methodsSeveral methods are supported for authenticating the request. For this use case, this should be limited to introspection.introspectionNo
config.cache_introspectionBoolean value that controls whether an introspection result should be cached.trueNo
config.introspect_jwt_tokensBoolean value that controls if JWTs sent in an Authorization header should also be introspected.falseNo
config.introspection_endpointEndpoint for introspection. Might be needed if discovery is not possible.https://idsvr.example.com/oauth/v2/oauth-introspectNo

Test the configuration

Any supported OAuth/OIDC flow can be used to obtain an opaque access token from the Curity Identity Server. Several approaches for obtaining a token are outlined in the Curity Getting Started Guide. Make sure that the token issued contains the openid scope.

Call the exposed service created earlier and pass the opaque access token in the Authorization header.

  1. curl -X GET http://kong:8000/httpbin/get \
  2. --header "Authorization: Bearer <OPAQUE ACCESS TOKEN"

Kong introspects the opaque token and receives the JWT in the response. The JWT is forwarded to the upstream API. Because the configured upstream API is httpbin, it is echoed back. The below sample response shows the phantom_token that contains the JWT and can be consumed by the API. The response is truncated for readability.

  1. {
  2. "args": {},
  3. "headers": {
  4. ...
  5. "Host": "httpbin.org",
  6. "Phantom-Token": "eyJraWQiOiIxN...",
  7. "X-Forwarded-Host": "localhost",
  8. "X-Forwarded-Path": "/httpbin/get",
  9. "X-Forwarded-Prefix": "/httpbin"
  10. },
  11. "origin": "172.27.0.1, 69.181.2.136",
  12. "url": "http://localhost/get"
  13. }

Resources