PingOne Platform APIs

Create a request property JWT

A request property JWT enables OIDC/OAuth2 request parameters to be passed as a single, self-contained parameter. Using a JWT enables integrity protection of parameters that are required for risk-based authentication or privacy and consent use cases.

You can create a request JWT using the following signing algorithms:

  • HS256, HS384, HS512

    Use this signing algorithm when an application’s client secret is the signing key.

  • RS256, RS384, RS512

    Use this signing algorithm when an external private key is used as the signing key.

For example, the request JWT for a transaction approval action takes the following parameters:

Parameter Description

Signing algorithm

Specifies the JWT signing algorithm. Options are HS256, HS384, HS512 and RS256, RS384, RS512.

Signing key

Specifies the signing key, which is the application’s clientSecret property value or an external private key.

--claims

Specifies the claims required by the token:

  • iss: A string that specifies the application ID of the issuer creating the token

  • aud: A string that specifies the intended audience for this token.

  • pi.template: A string that specifies the template name and the variables required by the template. For information refer to Notifications Templates.

  • pi.clientContext: A string that specifies the name-value pairs that define the client context. For information refer to Device Authentications.

  • pi.remoteIp: A string that specifies the user’s IP address. This is an optional property used with authentication policies that include IP-based conditions.

  • pi.webAuthn.challenge: Include this parameter if you want to use dynamic linking to attach a unique identifier to a FIDO transaction. The value should be a custom challenge to replace the automatically-generated challenge sent with the authentication request. Must be a valid and unique Base64URL string that decodes to a data array of at least 32 bytes. You can generate a challenge that meets these criteria by adding a random nonce to the transaction details to ensure uniqueness and then using SHA-256 to hash the information.

Request property JWT signed using the client secret

This sample shows the information required in a transaction approval JWT in which the JWT is signed using the PingOne client secret with HS256 encryption:

"jwtHeader": {
  "alg": "HS256",
  "typ": "JWT"
},
"jwtBody":
{
  "aud": "https://auth.pingone.com/{{envID}}/as",
  "iss": "{{appID}}",
  "pi.template": {
    "name": "transaction",
    "variant": "{{variantName}}",
    "variables": {
      "sum": "1,000,000",
      "currency": "USD",
      "recipient": "Charlie Parker"
    }
  },
  "pi.clientContext": {
    "alert.color": "red"
  }
}

This sample demonstrates the use of the pi.webAuthn.challenge parameter for using dynamic linking to attach a unique identifier to a FIDO transaction:

"jwtHeader": {
  "alg": "HS256",
  "typ": "JWT"
},
"jwtBody":
{
  "aud": "https://auth.pingone.com/{{envID}}/as",
  "iss": "{{appID}}",
  "pi.webAuthn": {
    "challenge": "1cd774777136450c97e83267a52cecccb5f52d1adbc0f46c42e164edadb47fb3"
  }
}

The following information describes the OIDC parameters and the steps for generating and signing the token.

Prerequisites

  1. Install a JWT token generator.

  2. Retrieve the environment id property value associated with your application and user.

  3. Retrieve the clientId and clientSecret property values for the application.

  4. Retrieve the name of the transaction notification template that you want to use.

For non-production applications, you can use the PingOne JWT Encoder located on the Developer Tools page (JWT Encoder) to generate a JSON Web Token. This utility asks you to provide values for the JWT header, the JWT payload (the set of claims), and the RSA private key. The JWT Encoder page provides detailed documentation about these three components.

Generate a signed token

  1. Run JWT token generator, providing the information above.

  2. Record the token returned successfully by the command to use as the value of the request property in the authorize request.

You can use the PingOne JWT Decoder located on the Developer Tools page (JWT Decoder) to view the claims information in a JSON Web Token. This utility asks you to provide the JWT token, and it returns a Header (the type of encoded object in the payload), the Payload (the JWT claims set), and the Signature (an encoding of the Header and Payload).

Request property JWT signed using a private key and JWKS string

This sample shows the information required in a transaction approval JWT in which the JWT is signed using an external private key with RS256 encryption:

"jwtHeader": {
  "alg": "RS256",
  "typ": "JWT"
},
"jwtBody":
{
  "aud": "https://auth.pingone.com/{{envID}}/as",
  "iss": "{{appID}}",
  "pi.template": {
    "name": "transaction",
    "variant": "{{variantName}}",
    "variables": {
      "sum": "1,000,000",
      "currency": "USD",
      "recipient": "Charlie Parker"
    }
  },
  "pi.clientContext": {
    "alert.color": "red"
  }
}

When you sign a request JWT using a private key and the RS256 (or RS384, RS512)signing algorithm, you must set the application’s jwks (or jwksUrl) property to sign the JWT. For information about the application configuration, refer to the OIDC settings data model properties table in Application Operations.

Generate a keypair

  1. Use a keypair generator to create a keypair with the following configuration options.

    • Key size: 2048

    • Key use: signature

    • Algorithm: RS256

    • Key-ID: SHA-256

    • Show X.509: No

  2. Save the generated Public and Private Keypair and the Public Key.

    • Example public and private keypair

      {
      "p": "x1mRR-Y1_i8ZPTLe2sPmuif4hhIfaxSph8m_iACDEHvAfTh0RMV7SrExscRSUXzcWX_FbSIKE5tDm4c1qzImnmWz06z6SSQYUjl0iU6V439sebR662deH5kOF92Vbtj5OLk-mNdj-fm6CdwnWEp3vb36T9kOiKHGReluwJpG1I8",
      "kty": "RSA",
      "q": "tY0osG4YzkzTX_NCxN3QBFinw_hvJLX6zVXZ-PGHTOD0iFsdwCzmqa3o6_4-GtHUSiuoboTscx2ItbU824IDp41p99HLvSm0lZixszqlcG1JZSaQVj5_5rOBttTcovvAL5te4jq5Mi966WC3yT-V_ZLxE3jFNt5vNzW8ykxsAJ8",
      "d": "T_2qcj4Tb-wuMCvI3uOvBZza21PjzkCy5iTClT3QZ30Wlwm8A35x1b3MVHz7JGox3I_KvMClwQdrDMU2aibQaGzs_EunMH5Y1VhlKDg4RvuQBoyB9lpDT1TdrmDe7kHDPDERrB84gPQkrAm-RgJ0W_zPyJMR013pZjOwPKlxKYbsW1G02Jbg2Vl1zatNWBm1MFYQYEOYyaNQkt32WktNdgixYg0Qdt3Q160mbfNz5c9USLVqvCsye0J2t9DZPK7WzadQCC4S7ehdmQkGd87IfD4XyKuZND_nE8Nz5nbgOLNfuIwR6QH7ksOHT9ur1JVKkzEkX8P40_7LXdarwraiBQ",
      "e": "AQAB",
      "use": "sig",
      "kid": "q3sWApYjHZQLmWMUdAIqZiVWSshDdau5eI4K_Bm65Us",
      "qi": "t06uC_ML8E01gKSeFPH7LNFxpumuIaYBc_Enr10dB-wqGpYfs6B5yqf5SjlXg1K89Z3QZFcU9AdJW0SYtr9T-A7b3csxeWUW98hOwfXentP8vcSv3dXJI753f64tAZqz5Mgd6jh0D8i1Fvg6d7Hqm_a5cfd-DO80QkW9c8u8rmk",
      "dp": "L95hFWvBQVUb8WcavltWNxNMCR2m77aZcuLOHCFLV5TvxuHcgXsOPQRJk4852RlrbA5TYP5Qfx7EYD9acs5rGZQAV27s9s01DeGAC0yUj3lUmfDtp0M-BcZh7PcnX-O4DJfm4RqvhiIiOyXjSL8w-5330l6jr8lw6-6-yn8BTR8",
      "alg": "RS256",
      "dq": "lFS9ftClEcCxHn7Y-ZGkyDhK8ZFD9YF9ZVCUY5GqksRk5hdTylSlLNL7L_0sbqsrQGJFHe8aZL8nmBZ4n3utUrL2dlSBmo69jVARN7ddvep8gdktKlmsFChrfZ6SmdMIZZ0Su9FwyDEEwjKUVifOezwYHWmZ78dypHASTFJ-F08",
      "n": "jWA_vDxg41NrYJdIiv3BcljMy7V15bMyOyK5aJov6FgUTE2Xm_B9SqJu55qmS3CxVhvYWSpRIZvhrgap19CE_VnrAc5pzwj2oSEmDRXXFSGmMjHAmfTXU66nDZVmhbtDIBkPU-h55RDZf6zIn3SPOrmWJYj0G5X2fMJfbUOpuROjH1aMqqGOxcT-dX-LA0dd94LrH4J-g1HFeGZqw-uyQO8l1g6fbQYVaNvnHtw9V7U7I684Ks-3sZcU-YhexNhiN53izIglhdVva9pjSTUk4BnmYtSlfyF6HzUYkvg3H1S0Y6LqzW8lOIw8SF-L6jQqkT2DPDwDbxzNoaNx8lIE0Q"
      }
    • Example public key

      {
      "kty": "RSA",
      "e": "AQAB",
      "use": "sig",
      "kid": "q3sWApYjHZQLmWMUdAIqZiVWSshDdau5eI4K_Bm65Us",
      "alg": "RS256",
      "n": "jWA_vDxg41NrYJdIiv3BcljMy7V15bMyOyK5aJov6FgUTE2Xm_B9SqJu55qmS3CxVhvYWSpRIZvhrgap19CE_VnrAc5pzwj2oSEmDRXXFSGmMjHAmfTXU66nDZVmhbtDIBkPU-h55RDZf6zIn3SPOrmWJYj0G5X2fMJfbUOpuROjH1aMqqGOxcT-dX-LA0dd94LrH4J-g1HFeGZqw-uyQO8l1g6fbQYVaNvnHtw9V7U7I684Ks-3sZcU-YhexNhiN53izIglhdVva9pjSTUk4BnmYtSlfyF6HzUYkvg3H1S0Y6LqzW8lOIw8SF-L6jQqkT2DPDwDbxzNoaNx8lIE0Q"
      }

Generate a signed JWT

  1. Create a signed JWT with Algorithm RS256 and header and payload information shown below.

    • Header

      {
       "alg": "RS256",
       "typ": "JWT"
      }
    • Payload (for the transaction approval example)

      {
       "aud": "https://auth.pingone.com/{{envID}}/as",
       "iss": "{{appID}}",
       "pi.template": {
         "name": "transaction",
         "variant": "{{variantName}}",
         "variables": {
           "sum": "1,000,000",
           "currency": "USD",
           "recipient": "Charlie Parker"
         }
      }
  2. Record the token returned successfully.

    The value for exp must be valid. It cannot be in the past, and it cannot be set more than one hour in the future.

  3. Record the token returned successfully by the command to use as the value of the request property in the authorize request.

Create the JWKS string

You will use the generated keys to create a JWKS string object that can be used as the value in your PingOne application’s jwks property.

  1. Copy the Public Key and wrap it like this:

    {
    "keys": [
      <Your public key>
     ]
    }

    Which looks like this:

    {
    "keys": [
       {
         "kty": "RSA",
         "e": "AQAB",
         "use": "sig",
         "kid": "q3sWApYjHZQLmWMUdAIqZiVWSshDdau5eI4K_Bm65Us",
         "alg": "RS256",
         "n": "jWA_vDxg41NrYJdIiv3BcljMy7V15bMyOyK5aJov6FgUTE2Xm_B9SqJu55qmS3CxVhvYWSpRIZvhrgap19CE_VnrAc5pzwj2oSEmDRXXFSGmMjHAmfTXU66nDZVmhbtDIBkPU-h55RDZf6zIn3SPOrmWJYj0G5X2fMJfbUOpuROjH1aMqqGOxcT-dX-LA0dd94LrH4J-g1HFeGZqw-uyQO8l1g6fbQYVaNvnHtw9V7U7I684Ks-3sZcU-YhexNhiN53izIglhdVva9pjSTUk4BnmYtSlfyF6HzUYkvg3H1S0Y6LqzW8lOIw8SF-L6jQqkT2DPDwDbxzNoaNx8lIE0Q"
       }
     ]
    }
  2. The string needs to be reduced to one line and the double quotes escaped.

    The JSON for the PingOne application POST (or PUT) to create the application looks like:

    {
      ...
      "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
       "jwks": "{ \"keys\": [ { \"kty\": \"RSA\", \"e\": \"AQAB\", \"use\": \"sig\", \"kid\": \"q3sWApYjHZQLmWMUdAIqZiVWSshDdau5eI4K_Bm65Us\", \"alg\": \"RS256\", \"n\": \"jWA_vDxg41NrYJdIiv3BcljMy7V15bMyOyK5aJov6FgUTE2Xm_B9SqJu55qmS3CxVhvYWSpRIZvhrgap19CE_VnrAc5pzwj2oSEmDRXXFSGmMjHAmfTXU66nDZVmhbtDIBkPU-h55RDZf6zIn3SPOrmWJYj0G5X2fMJfbUOpuROjH1aMqqGOxcT-dX-LA0dd94LrH4J-g1HFeGZqw-uyQO8l1g6fbQYVaNvnHtw9V7U7I684Ks-3sZcU-YhexNhiN53izIglhdVva9pjSTUk4BnmYtSlfyF6HzUYkvg3H1S0Y6LqzW8lOIw8SF-L6jQqkT2DPDwDbxzNoaNx8lIE0Q\" } ]}",
      ...
    }

Configure the JWKS URL

To use the jwksUrl property in the PingOne application’s configuration, the JWKS string must be hosted on a web server, accessible to the internet (using https://). For testing purposes, the following code sample shows a simple node server file (running on a local web server) that hosts the JWKS string.

const https = require("https");
const host = 'localhost';
const port = 3000;

const requestListener = function (req, res) {
    res.setHeader("Content-Type", "application/json");
    res.writeHead(200);

    const jwksString = "{\r\n  \"keys\": [\r\n    {\r\n        \"kty\": \"RSA\",\r\n        \"e\": \"AQAB\",\r\n        \"use\": \"sig\",\r\n        \"kid\": \"q3sWApYjHZQLmWMUdAIqZiVWSshDdau5eI4K_Bm65Us\",\r\n        \"alg\": \"RS256\",\r\n        \"n\": \"jWA_vDxg41NrYJdIiv3BcljMy7V15bMyOyK5aJov6FgUTE2Xm_B9SqJu55qmS3CxVhvYWSpRIZvhrgap19CE_VnrAc5pzwj2oSEmDRXXFSGmMjHAmfTXU66nDZVmhbtDIBkPU-h55RDZf6zIn3SPOrmWJYj0G5X2fMJfbUOpuROjH1aMqqGOxcT-dX-LA0dd94LrH4J-g1HFeGZqw-uyQO8l1g6fbQYVaNvnHtw9V7U7I684Ks-3sZcU-YhexNhiN53izIglhdVva9pjSTUk4BnmYtSlfyF6HzUYkvg3H1S0Y6LqzW8lOIw8SF-L6jQqkT2DPDwDbxzNoaNx8lIE0Q\"\r\n    }\r\n  ]\r\n}";

    res.end(jwksString);
};

const server = https.createServer(requestListener);
server.listen(port, host, () => {
    console.log(`Server is running on https://${host}:${port}`);
});

With the JWKS string in a known location, the application configuration JSON looks like this:

{
  ...
  "tokenEndpointAuthMethod": "PRIVATE_KEY_JWT",
  "jwksUrl": "https://{{pathToJwksString}}",
  ...
}