PingGateway 2024.9

ID token validation

This page uses an IdTokenValidationFilter to validate an ID token.

  1. Set up AM:

    1. Set up AM as described in Validate access tokens with introspection.

    2. Select Applications > OAuth 2.0 > Clients and add the additional scope openid to client-application.

  2. Set up PingGateway:

    1. Add the following route to PingGateway:

      • Linux

      • Windows

      $HOME/.openig/config/routes/idtokenvalidation.json
      %appdata%\OpenIG\config\routes\idtokenvalidation.json
      {
        "name": "idtokenvalidation",
        "condition": "${find(request.uri.path, '^/idtokenvalidation')}",
        "capture": "all",
        "handler": {
          "type": "Chain",
          "config": {
            "filters": [{
              "type": "IdTokenValidationFilter",
              "config": {
                "idToken": "<id_token_value>",
                "audience": "client-application",
                "issuer": "http://am.example.com:8088/openam/oauth2",
                "failureHandler": {
                  "type": "ScriptableHandler",
                  "config": {
                    "type": "application/x-groovy",
                    "source": [
                      "def response = new Response(Status.FORBIDDEN)",
                      "response.headers['Content-Type'] = 'text/html; charset=utf-8'",
                      "def errors = contexts.jwtValidationError.violations.collect{it.description}",
                      "def display = \"<html>Can't validate id_token:<br> ${contexts.jwtValidationError.jwt} \"",
                      "display <<=\"<br><br>For the following errors:<br> ${errors.join(\"<br>\")}</html>\"",
                      "response.entity=display as String",
                      "return response"
                    ]
                  }
                },
                "verificationSecretId": "verify",
                "secretsProvider": {
                  "type": "JwkSetSecretStore",
                  "config": {
                    "jwkUrl": "http://am.example.com:8088/openam/oauth2/connect/jwk_uri"
                  }
                }
              }
            }],
            "handler": {
              "type": "StaticResponseHandler",
              "config": {
                "status": 200,
                "headers": {
                  "Content-Type": [ "text/html; charset=UTF-8" ]
                },
                "entity": "<html><body>Validated id_token:<br> ${contexts.jwtValidation.value}</body></html>"
              }
            }
          }
        }
      }

      Notice the following features of the route:

      • The route matches requests to /idtokenvalidation.

      • A SecretsProvider declares a JwkSetSecretStore to validate secrets for signed JWTs. The JwkSetSecretStore specifies a URL to a JWK set on AM that contains the signing keys.

      • The property verificationSecretId is configured with an arbitrary value. If this property isn’t configured, the filter doesn’t verify the signature of tokens.

      • The JwkSetSecretStore specifies the URL to a JWK set on AM, that contains verification keys identified by a kid. PingGateway validates the token signature as follows:

        • If the value of a kid in the JWK set matches a kid in the the signed JWT, the JwkSetSecretStore verifies the signature.

        • If the JWT doesn’t have a kid, or if the JWK set doesn’t contain a key with the same value, the JwkSetSecretStore looks for valid secrets with the same purpose as the value of verificationSecretId.

      • If the filter validates the token, the StaticResponseHandler displays the token value from the context ${contexts.jwtValidation.value}. Otherwise, the ScriptableHandler displays the token value and a list of violations from the context ${contexts.jwtValidationError.violations}

  3. Test the setup:

    1. In a terminal window, use a curl command similar to the following to retrieve an id_token:

      $ curl -s \
      --user "client-application:password" \
      --data "grant_type=password&username=demo&password=Ch4ng31t&scope=openid" \
      http://am.example.com:8088/openam/oauth2/access_token
      
      {
       "access_token":"...",
       "scope":"openid",
       "id_token":"...",
       "token_type":"Bearer",
       "expires_in":3599
      }
    2. In the route, replace <id_token_value> with the value of the id_token returned in the previous step.

    3. In your browser’s privacy or incognito mode, go to https://ig.example.com:8443/idtokenvalidation.

      The validated token is displayed.

    4. In the route, invalidate the token by changing the value of the audience or issuer, and then access the route again.

      The value of the token, and the reasons that the token is invalid, are displayed.