Note: Signature validation is only required for tokens not received directly from the token endpoint (i.e. for the Implicit Client Profile). In other cases where the id_token is received directly by the client from the token endpoint over HTTPS, transport layer security should be sufficient to vouch for the integrity of the token.

The ID token is signed according to the JSON Web Signature (JWS) specification; algorithms used for signing are defined in the JSON Web Algorithm (JWA) specification. PingFederate 7.1 can support the following signing algorithms:

"alg" Value Signature Method Signing Key
NONE No Digital Signature N/A
HS256 HMAC w/ SHA-256 hash Uses the client secret of the OAuth2 client
HS384 HMAC w/ SHA-384 hash Uses the client secret of the OAuth2 client
HS512 HMAC w/ SHA-512 hash Uses the client secret of the OAuth2 client
RS256 RSA PKCS v1.5 w/ SHA-256 hash Public key available from the JWKS (see below)
RS384 RSA PKCS v1.5 w/ SHA-384 hash Public key available from the JWKS (see below)
RS512 RSA PKCS v1.5 w/ SHA-512 hash Public key available from the JWKS (see below)
ES256 ECDSA w/ P-256 curve and SHA-256 hash Public key available from the JWKS (see below)
ES384 ECDSA w/ P-384 curve and SHA-384 hash Public key available from the JWKS (see below)
ES512 ECDSA w/ P-521 curve and SHA-512 hash Public key available from the JWKS (see below)
Note: RS256 is the default signature algorithm.

The basic steps to verify a digital signature involve retrieving the appropriate key to use for the signature verification and then performing the cryptographic action to verify the signature.

To validate the signature, take the JWT header and the JWT payload and join with a period. Validate that value against the third component of the JWT using the algorithm defined in the JWT header. Using the above ID token as an example:

Signed data (JWT Header + "." + JWT Payload):


eyJhbGciOiJSUzI1NiIsImtpZCI6Imkwd25uIn0.eyJzdWIiOiJqb2UiLCJhdWQiOiJpbV9vaWNfY2xpZW50IiwianRpIjoidWY5MFNLNHdz
Y0ZoY3RVVDZEdHZiMiIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTAzMSIsImlhdCI6MTM5NDA2MDg1MywiZXhwIjoxMzk0MDYxMTUz
LCJub25jZSI6ImU5NTdmZmJhLTlhNzgtNGVhOS04ZWNhLWFlOGM0ZWY5Yzg1NiIsImF0X2hhc2giOiJ3Zmd2bUU5VnhqQXVkc2w5bGM2VHFB
In0

Signature value to verify:


lr4L-oT7DJi7Re0eSZDstAdOKHwSvjZfR-OpdWSOmsrw0QVeI7oaIcehyKUFpPFDXDR0-RsEzqno0yek-_U-Ui5EM-yv0PiaUOmJK1U-ws_C
-fCplUFSE7SK-TrCwaOow4_7FN5L4i-4NAa_WqgOjZPloT8o3kKyTkBL7GdITL8rEe4BDK8L6mLqHJrFX4SsEduPk0CyHJSykRqzYS2MEJln
cocBBI4up5Y5g2BNEb0aV4VZwYjmrv9oOUC_yC1Fb4Js5Ry1t6P4Q8q_2ka5OcArlo188XH7lMgPA2GnwSFGHBhccjpxhN7S46ubGPXRBNsn
rPx6RuoR2cI46d9ARQ
      
Note: The actual implementation of the signing algorithm used to validate the signature will be implementation specific. It is recommended to use a published library to perform the signature verification.

For symmetric key signature methods, the client secret value for the OAuth2 client is used as the shared symmetric key. For this reason the client secret defined for the OAuth2 client must be of a large enough length to accommodate the appropriate algorithm (i.e. for a SHA256 hash, the secret must be at least 256 bits "“ 32 ASCII characters).

Asymmetric signature methods require the application to know the corresponding public key. The public key can be distributed out-of-band or can be retrieved dynamically via the JSON Web Key Set (JWKS) endpoint as explained below:

1. Determine the signing algorithm (alg) and the key identifier (kid) from the JWT header. Using the sample JWT token above as an example, the following values are known:

OpenID Connect issuer https://localhost:9031
Signing algorithm (alg) RS256
Key reference identifier (kid) i0wnn

2. Query the OpenID configuration URL for the location of the JWKS:


GET https://localhost:9031/.well-known/openid-configuration HTTP/1.1
      

this will result in a HTTP response containing the OpenID Connect configuration for the OpenID Connect Provider (OP) :


HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "version":"3.0",

  "issuer":"https:\/\/localhost:9031",

  "authorization_endpoint":"https:\/\/localhost:9031\/as\/authorization.oauth2",

  "token_endpoint":"https:\/\/localhost:9031\/as\/token.oauth2",

  "userinfo_endpoint":"https:\/\/localhost:9031\/idp\/userinfo.openid",

  "jwks_uri":"https:\/\/localhost:9031\/pf\/JWKS",

  "scopes_supported":["phone","address","email","admin","edit","openid","profile"],

  "response_types_supported":["code","token","id_token","code token",
    "code id_token","token id_token","code token id_token"],

  "subject_types_supported":["public"],

  "id_token_signing_alg_values_supported":["none","HS256","HS384","HS512","RS256",
    "RS384","RS512","ES256","ES384","ES512"],

  "token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],

  "claim_types_supported":["normal"],

  "claims_parameter_supported":false,

  "request_parameter_supported":false,

  "request_uri_parameter_supported":false
}

      

3. Parse the JSON to retrieve the jwks_uri value (bolded above) and make a request to that endpoint, JSON Web Keystore (JWKS), to retrieve the public key for key identifier "i0wnn" and key type (kty) of RSA as the algorithm is RS256 that was used to sign the JWT:


GET https://localhost:9031/pf/JWKS HTTP/1.1
      

Which will return the JWKS for the issuer:


HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "keys":[
    {
      "kty":"EC",
      "kid":"i0wng",
      "use":"sig",
      "x":"AXYMGFO6K_R2E3RH42_5YTeGYgYTagLM-v3iaiNlPKFFvTh17CKQL_OKH5pEkj5U8mbel-0R1YrNuraRXtBztcVO",
      "y":"AaYuq27czYSrbFQUMo3jVK2hrW8KZ75KyE8dyYS-HOB9vUC4nMvoPGbu2hE_yBTLZLpuUvTOSSv150FLaBPhPLA2",
      "crv":"P-521"
    },
    ...
    {
      "kty":"RSA",
      "kid":"i0wnn",
      "use":"sig",
      "n":"mdrLAp5GR8o5d5qbwWTYqNGuSXHTIE6w9HxV445oMACOWRuwlOGVZeKJQXHM9cs5Dm7iUfNVk4pJBttUxzcnhVCRf
      9tr20LJB7xAAqnFtzD7jBHARWbgJYR0p0JYVOA5jVzT9Sc-j4Gs5m8b-am2hKF93kA4fM8oeg18V_xeZf11WWcxnW5YZwX
      9kjGBwbK-1tkapIar8K1WrsAsDDZLS_y7Qp0S83fAPgubFGYdST71s-B4bvsjCgl30a2W-je9J6jg2bYxZeJf982dzHFqV
      QF7KdF4n5UGFAvNMRZ3xVoV4JzHDg4xe_KJE-gOn-_wlao6R8xWcedZjTmDhqqvUw",
      "e":"AQAB"
    },
    ...
  ]
}

We now have the modulus (n) and the exponent (e) of the public key. This can be used to create the public key and validate the signature.

Note: The public key can be stored in secure storage (i.e. in the keychain) to be used for verification of the id_token when a user is offline.