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 |
Signing key |
Specifies the signing key, which is the application’s |
|
Specifies the claims required by the token:
|
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
-
Install a JWT token generator.
-
Retrieve the environment
idproperty value associated with your application and user. -
Retrieve the
clientIdandclientSecretproperty values for the application. -
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
-
Run JWT token generator, providing the information above.
-
Record the token returned successfully by the command to use as the value of the
requestproperty 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 |
Generate a keypair
-
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
-
-
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
-
Create a signed JWT with
Algorithm RS256and 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" } }
-
-
Record the token returned successfully.
The value for
expmust be valid. It cannot be in the past, and it cannot be set more than one hour in the future. -
Record the token returned successfully by the command to use as the value of the
requestproperty 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.
-
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" } ] } -
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}}",
...
}