|docs
Start Trial

Developer

PagerDuty OpenID ID Token

PagerDuty OpenID ID Token

PagerDuty uses ID Tokens as defined by the OpenID specification to securely provide additional details (also called claims) associated with your access token, such as the account subdomain and service region. These tokens are structured as JSON Web Tokens (JWT). The token is encoded and signed by PagerDuty.

URL NameURLDescription
Public Key URLhttps://identity.pagerduty.com/global/oauth/anonymous/jwksUse the public key to verify that the token is unmodified and sent by PagerDuty
Open ID Configurationhttps://identity.pagerduty.com/global/oauth/anonymous/.well-known/openid-configurationAdditional details on OpenID features supported by PagerDuty

The ID token will be returned with the access token on a successful call to oauth/token:

eyJraWQiOiIxNzg3MzQ1MDA4IiwieDV0IjoiX2Nxbk1aWlBBcEF0V3kyVm11T1Y4dUc5VHNvIiwiYWxnIjoiUlMyNTYifQ.eyJleHAiOjE2NDYwODYyNjAsIm5iZiI6MTY0NjA4MjY2MCwianRpIjoiYTlmZDQzYTQtYjAzNy00ZWViLTk4YjAtNDA1NDJlM2I5OGZmIiwiaXNzIjoiaHR0cHM6Ly9hcHAucGQtc3RhZ2luZy5jb20vZ2xvYmFsL29hdXRoL2Fub255bW91cyIsImF1ZCI6WyJodHRwczovL2FwaS5wZC1zdGFnaW5nLmNvbSIsIjkwYjE1M2JmLWNmZWItNDgzNy04YjZhLTg2NGI3ZmY4NTY1NiJdLCJzdWIiOiJmdGFudGF3aUBwYWdlcmR1dHkuY29tIiwiYXV0aF90aW1lIjoxNjQ2MDgyNjQ5LCJpYXQiOjE2NDYwODI2NjAsInB1cnBvc2UiOiJpZCIsImF0X2hhc2giOiJMTXRGS01MWWVGZXppTnR4OVBKV0hBIiwiYWNyIjoiYWNyOmh0bWwtZm9ybTp1bml0ZWRzdGF0ZXMiLCJkZWxlZ2F0aW9uX2lkIjoiNjU2NjAyN2QtNzcwNy00MjhmLTg3NTItM2VmOTcxYjc4ZDFhIiwiYWNjb3VudF9pZCI6IlA5SkVITUsiLCJ1c2VyX2lkIjoiUDhPR01JSyIsImF6cCI6IjkwYjE1M2JmLWNmZWItNDgzNy04YjZhLTg2NGI3ZmY4NTY1NiIsImFtciI6ImFjcjpodG1sLWZvcm06dW5pdGVkc3RhdGVzIiwic3ViZG9tYWluIjoicGR0LWZhcmVzIiwicmVnaW9uIjoiVW5pdGVkU3RhdGVzIiwic2lkIjoiTGR1Mm03RnFuUDdjSDZHbCJ9.uhbXVou8raKUtx56D8pGmWn3VyX8X1ZhadKYAwftcnc5DNHvEXco8MJKle8w5a1v1f9l881eGHLCsrRUb-B0AOHsWVF0EJTGOhWKgVpx9_SrsGXa7qyVlS3fBh-Gh2IrvDHTBWfe2bQ2g_qEfvCneIBIaELVdOeCysxMShygYgd7iOWwM6m3KGNrtCM4RK0JqYSdTRFpXP-OCBVy6JenJqK3maevffi0-7Z0Q0XFuMIwRR-M3A90Wt9349AhwXNK2kL7mvI3ZltnuomoTcB6rRMUylTp7YXyFjhc4nwA8ZlBw6T8SYPvjXy7iRE0ud4TxEh0J_bfs0gOfqgvKY47aQ

The main parts of the ID token are the following:

NameDescription
HeaderContains token metadata such as the type of token and hash used
PayloadContains the user, authorization, and claims
SignatureUsed to verify the token and check for tampering

Each part of the token is encoded using the algorithm specified in the header, split by .. Every part is structured in the JSON format.

The header includes three fields. The algorithm used to encrypt and decrypt the token is a variant of SHA-256 called RS256, and is declared as the first part of the header. The next part of the header is the Key ID, which is later used for verification. The last part is the certificate (x5t) which is base64url encoded. Putting these parts together, the header is formed.

The main purpose of the header is to determine a decoding algorithm to use for the rest of the token and what key is used for validation. All valid header parameters can be found here, but the most common ones are the following:

ClaimDescription
algAlgorithm used for signature of the token
kidAt a given point, PagerDuty may support multiple signing keys. This id identifies which signing key was used for this token.
x5tFingerprint of the certificate used

In the sample ID token above, the header portion is the first section:

eyJraWQiOiIxNzg3MzQ1MDA4IiwieDV0IjoiX2Nxbk1aWlBBcEF0V3kyVm11T1Y4dUc5VHNvIiwiYWxnIjoiUlMyNTYifQ

After being base64 decoded, the sample JSON header looks something like this:

{
  "alg": "RS256",
  "kid": "1787345008",
  "x5t": "_cqnMZZPApAtWy2VmuOV8uG9Tso"
}

Payload

The payload contains claims about the access token, which are statements about the user along with any additional data needed. PagerDuty uses two types of claims:

TypeDescription
Registered ClaimsPredefined recommended claims that are reserved by the JWT standard. The most common ones used are iss (issuer), aud (audience), sub (subject), exp (expiration time). Some of the less common ones are nbf (not before), iat (issued at), and jti (JWT ID).
Private ClaimsPagerDuty includes a number of private claims related to the user and account for convenience.

The claims included in the PagerDuty ID Token are described here in detail:

ClaimDescription
expExpiry time, in a Unix timestamp
nbfUnix timestamp that identifies the time before the ID Token must NOT be accepted (not before)
jtiUnique JWT ID
issThe principal/issuer that issued the ID Token. This should always be https://identity.pagerduty.com/global/oauth/anonymous.
audIntended reciever of the token (audience). For PagerDuty ID Tokens, this will include a URL specific to the account's service region, either https://api.pagerduty.com or https://api.eu.pagerduty.com, as well as the client ID.
subSubject of the ID Token. For PagerDuty ID tokens, this can be used to uniquely identify the user that authorized the oauth client.
auth_timeTime when authentication occurred, in a Unix timestamp
iatTime when the ID Token was issued, in a Unix timestamp
purposePurpose of the JWT. For PagerDuty ID tokens, this is always identification.
at_hashHash value of corresponding access token issued
acrThe authentication context class reference, which gives context about how the user authenticated the oauth client.
delegation_idA delegation represents that authorization was granted by a user to your oauth client, similar to a session. It will be consistent across the history of all access tokens and refresh tokens for that authorization.
account_idPagerDuty account ID linked to the token
user_idPagerDuty user ID linked to the token
azpThe authorized party that was issued the ID Token, which is the client ID
amrAuthentication method references. Similar to the acr field, this gives context about how the user authenticated the oauth client.
subdomainPagerDuty subdomain linked to the ID token
regionUser and account service region
sidSession ID

Here is a sample decrypted payload for a PagerDuty ID token:

{
  "exp": 1646086260,
  "nbf": 1646082660,
  "jti": "a9fd43a4-b037-4eeb-98b0-40542e3b98ff",
  "iss": "https://identity.pagerduty.com/global/oauth/anonymous",
  "aud": [
    "https://api.pagerduty.com",
    "90b153bf-cfeb-4837-8b6a-864b7ff85656"
  ],
  "sub": "example@pagerduty.com",
  "auth_time": 1646082649,
  "iat": 1646082660,
  "purpose": "id",
  "at_hash": "LMtFKMLYeFeziNtx9PJWHA",
  "acr": "acr:html-form:unitedstates",
  "delegation_id": "6566027d-7707-428f-8752-3ef971b78d1a",
  "account_id": "P9JEHMK",
  "user_id": "P8OGMIK",
  "azp": "90b153bf-cfeb-4837-8b6a-864b7ff85656",
  "amr": "acr:html-form:unitedstates",
  "subdomain": "pdt-sample",
  "region": "UnitedStates",
  "sid": "Ldu2m7FqnP7cH6Gl"
}

Signature

The signature is used to verify that the message still has its original integrity and hasn't been tampered with and is sent from a trusted issuer.

You can find the public key that PagerDuty uses to sign the token at the following URL: https://identity.pagerduty.com/global/oauth/anonymous/jwks Please note however that the signing key could be rotated at any time, so we would recommend fetching the signing key from PagerDuty on each use instead of storing it locally.

This signature is created using the hash algorithm from the header, and to verify a token, you must do the following:

  • Retrieve the algorithm used to hash the token from the header
  • Use the x5t or kid parameter from the header to retrieve the public key
  • Seperate the signature from the message
  • Convert the remaining parts to an ASCII array
  • Decode the signature using Base64Url
  • Use the decoded signature to validate the ASCII array generated previously

Decoding the full ID token with Node and Javascript

Once an ID token has been received from PagerDuty, it can be decrypted. The following code sample uses jsonwebtoken, jwks-rsa, and node https to fetch the public PagerDuty key, verify the signature on the ID Token, and returns a Promise that contains the extracted payload details.

function verifyAndExtractIdTokenPayload(oauthTokenResponseJson) {
  const jwt = require('jsonwebtoken');
  const jwksClient = require('jwks-rsa');
  const https = require('https');

  const { idToken, domain, jwtIssuer } = oauthTokenResponseJson;

  return new Promise((resolve, reject) => {
    https.get('https://identity.pagerduty.com/global/oauth/anonymous/jwks', (jwksResponse) => {
      let jwksData = '';

      jwksResponse.on('data', (chunk) => {
        jwksData += chunk;
      });

      jwksResponse.on('end', () => {
        const client = jwksClient({
          jwksUri: JSON.parse(jwksData).jwks_uri
        });

        jwt.verify(
          idToken,
          async (header, cb) => {
            const key = await client.getSigningKey(header.kid);
            const signingKey = key.getPublicKey();
            cb(null, signingKey);
          },
          { algorithms: ['RS256'], issuer: jwtIssuer },
          (err, decodedToken) => {
            if (err) {
              reject(`ID Token signature validation failed due to ${err}`);
            } else {
              resolve(decodedToken);
            }
          }
        );
      }).on('error', (err) => {
        reject(`Fetching the PagerDuty public key failed due to ${err}`);
      });
    });
  };
}