Generate Public Private Key Pair For Jwt

Posted on  by
Generate Public Private Key Pair For Jwt Rating: 6,7/10 5138 reviews
  1. Nov 06, 2019  It's also possible to generate keys using openssl only: openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout -out public.pem.
  2. Jun 10, 2019  But I also forget how to generate a new token (private and public keys). Which is a common task as you should have a different token in your development (optional test) and production environment. If you want to store the keys in config/jwt (as you would in a symfony project), just run the following commands.
  3. Mkjwk simple JSON Web Key generator.
  4. 2 Generate a private and public key pair: Go to the Windows Start menu - All Programs - PuTTY and open PuTTYgen Click the 'Generate' button and PuTTYgen will ask you to make some random movement with your mouse until it has enough random data to generate a secure key for you.
  5. Generate a JSON Web Token (JWT)/RSA Token by following these steps: 1. From Terminal, run the following 2 commands to create an RSA key pair (Figure 1): openssl genrsa -out mykey.pem 4096. Openssl rsa -in mykey.pem -pubout -out pubkey.pem.

Using the JWT OAuth Flow requires you to:

Instead of using static keys and/or worrying about key distribution, the server generates a public/private key pair upon startup itself and just keeps it in memory. The keys will be reset and thereby all existing tokens invalidated when the server restarts, which is fine for the intended use case. The key pair is generated using pycrypto.

  • Generate a public/private key pair
  • Create a Connected App
  • Generate a JWT signing it with the private key
  • Exchange the JWT for an access token
  • Use the access token as a Bearer token

Below there is a section for each of the above steps.

Generate public/private key pair

Generate a public/private keypair using openssl and fill in the required info when you generate the certificate.

Create a Connected App

In Salesforce create a Connected App through the App Manager in Setup and upload the public key (public_key.cer from the above steps) to the app. Be sure to select the offline_access scope as well as other required scopes. For testing the openid scope is always good. Save the Connected App and make a note of the consumer key (client_id).

Generate a JWT

Use the node.js app in this repo to create a JWT. Once you've cloned the repo create a .env file with the followingkeys:

  • SUBJECT (the username of the user to impersonate)
  • CLIENT_ID (the consumer key (client_id) of the Connected App you created)
  • optional AUDIENCE (https://login.salesforce.com or https://test.salesforce.com as appropriate)
  • PATH_PRIVATE_KEY (path to the pem-file with the private key (private_key.pemfrom above))
  • PATH_PUBLIC_KEY (path to the pem-file with the public key (public_key.pemfrom above))

Please note: The JWT expires in 5 minutes so be quick about exchanging it for an access token!

Exchange the JWT for an access token

Using Postman or similar post to the OAuth token-endpoint of Salesforce specifying a grant_type-parameter of urn:ietf:params:oauth:grant-type:jwt-bearer and specify the JWT in the assertion parameter.

Gta

Use the access token as a Bearer token

Using with Azure

Using JWT's are also possible with Micrsoft Azure using the client_credentials flow specifying a JWT instead of a client_secret. To do this you must have uploaded the public key to the App Registation in Azure AD and you must specify a certificate thumbprint in the x5t key in the JWT header. The thumbprint is specified using CERTIFICATE_THUMBPRINT in the .env file and may be generated using openssl using a somewhat special process as it is not simply the sha1 hash as described in the documentation (https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials).

The hash to specify may be generated as follows as per https://stackoverflow.com/a/52625165

Using the above exchange the JWT for an access token using a POST like below:

This guide will walk you through the steps of implementing Public Key Client Validation. We include sample cURL commands and HTTP requests, then at the end we'll detail the steps in Java.

Public key client validation quickstart

To get started quickly, you can follow the Java example at the bottom of the page. It shows how Client Validation can be implemented, along with links to the Twilio Java helper library that supports this feature.

Steps to send a Request

  1. Generate an RSA Key Pair: Create a valid key pair. (This only has to be done once.)
  2. Submit the Public Key: Submit the public key to the Twilio via the Credentials Endpoint. (This is a one time requirement as well.)
  3. Hash the Canonical Request: Every outgoing request needs to be hashed and signed. (This functionality is implemented in the Java helper library and can be seen below.)
  4. Generate JWT: Once the hash is created, it needs to be embedded in the JWT payload and signed with the private key. (This is also handled by the Java helper library.)
  5. Attach JWT to the request header: The last step is to add the JWT to the request header.

1. Generate an RSA Keypair

A private key is used to sign your requests. It is is verified by the public key which you provide to Twilio.

Note: When you generate the private key, be sure to save and protect it as this is the only means to verify your application's identity.

We recommend generating the RSA key pair using the OpenSSL toolkit.

For Windows Systems

Install and use Cygwin to run the OpenSSL RSA keypair commands below.

For Mac and Linux/Unix-based Systems

You can run the OpenSSL commands to generate an RSA Keypair.

Generate a Private Key

Note: Twilio will only accept keys which have a bit length of 2048 with an exponent of 65537.

Generating a Public Key

Example Public Key FormatIf properly generated, the RSA public key should look like the example public key below:

Be sure to include the full header and footer when submitting the key: * '-----BEGIN PUBLIC KEY-----' AND * '-----END PUBLIC KEY-----'

2. Submit the Public Key to Twilio

Sample Requests cURL

Note: Line breaks in the PEM format of the key need to be removed when making the cURL request.

Sample Response

3. Hash the Canonical Request

The following section describes how the request needs to be canonicalized, hashed and attached to the request.

_Note: The Java helper library implements this functionality and will do the work for you. An end-to-end example is on the bottom of this page. _

This approach is loosely based on the approach Amazon is using to sign AWS API requests.

Canonical request pseudocode

Hashing Example

Example HTTP Request

Canonicalize the HTTP Method

The HTTP method is canonicalized by doing the following operations:

  1. Uppercase
  2. Trim

In the Example Request, this results in:

Canonicalize the Resource Path

To canonicalize the resource path:

  1. Remove redundant path elements, for example:
    • '/foobar/./barfoo' becomes '/foobar/barfoo' AND
    • '/foobar/./barfoo' becomes '/barfoo'
  2. URL-encode the remaining path using the UTF-8 character set in accordance with RFC 3986 with the following caveats:
    • ' ' (space) should always be '%20'
    • '*' (asterisk) should always be '%2A'
    • '%7E' should always be '~' (tilde)
  3. Empty string path should always result in ‘/’

In the Example Request, this results in:

Canonicalize the Query String

The query-string is canonicalized by the following operations:

  1. Remove the query-string from the URI (not-including the ‘?’)
  2. Construct a collection of key/value pairs by splitting the query string on ‘&’ASCII Sort the combined “key=value” strings (not just the ‘keys’)
  3. URL encode each key and value following the Resource Path (RFC 3986) with our caveats from above
  4. Concatenate each key/value pair like this: {key}={value}
    • If the key has no accompanying value, should result in ‘{key}=’Join all key/value pairs with a ‘&’ in between

In the example request, this results in the empty string.

If a request contains the following query parameter,

The canonicalized query string would be the following:

Canonicalize the Headers

The headers are canonicalized by the following operations:

  1. Filter the complete list of headers against the ‘hrh’ (hashed request headers) value in the enclosing JWT
  2. Lower-case and trim each header key
  3. Trim each header value and reduce continuous whitespace into a since space
  4. Sort header values that correspond to the same key
  5. Combine the key/values like this: “{key}:{values}n”
  6. ASCII sort
  7. Note that because each header line is terminated with a ‘n’. When the entire canonical request is combined, there should be a blank-line between the canonical-headers and the canonical-hashed-headers

In the Example Request, this results in:

Canonicalize the Hashed Headers

The hashed-headers are canonicalized by the following operations:

  1. Split on ‘;’ (semi-colon)
  2. Lowercase and trim
  3. 1ASCII Sort
  4. Join with ‘;” (semi-colon)

In the Example Request assume the want to include ‘Host’ and ‘Authorization’ in the list of hashed-headers, this results in:

Encode the Request Body

If the request body is empty, omit hashing it.

To encode the request body:

  1. Hash the request body using SHA-256
  2. Hex-encode the resulting hash

In the Example Request, this results in:

Final Canonical Request

In the example below, the first blank line is due to not having any query parameters. The second blank line is due to every canonicalized header being terminated with a ‘n’.

Canonical Request Hash

When the final canonical request string is created it must be hashed in a similar manner to the request body.

To encode the canonical request:

  1. Hash the request body using SHA-256
  2. Hex-encode the resulting hash

In the Example Request, this results in:

4. Generate the JWT

Once you have created the hash, you can generate a JWT with the hash embedded.

Every JWT assertion is composed of three components, the header, the payload, and the signature.

  • The header specifies the algorithm used for the JWT signature.
  • The payload contain the hash and additional metadata
  • The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.

To construct the JWT assertion, these three components must be base64 encoded and concatenated using a “.” separator:

Note: For additional details on JWT go to: https://jwt.io/introduction/

Let’s have a closer look at the different parts of the JWT Assertion:

Header

The header consists of four parts: the content type, type of the token, the hashing algorithm being used, and the reference to the public key Twilio should used validate the message.

FieldValue(s)RequiredDescription
ctytwilio-pkrv;v=1yesContentType = Twilio Public Key Request Validation - Version 1
typJWTNo (Default: ‘JWT’)Media Type = JSON Web Token, other values rejected
algRS256yesAlgorithm = RSASSA-PKCS-v1_5 using SHA-256 hash algorithm. This is the only algorithm supported at the moment.
kidCredentialSidyesKey ID = Identifier of the public key credential associated with the private key used to sign the JWT

Example header:

Payload

The second part of the token is the payload, which contains the claims. Claims are statements about an entity and additional metadata.

FieldValue(s)RequiredDescription
issAPIKeySidyesIssuer = APIKey Sid used to match against request credentials
subAccountSidyesSubject = AccountSid
expexpiration timeyesToken Expiry Time: token received after exp +- clock skew will be rejected. Max exp - nbf is 300 seconds
nbfnot before timeNo(Default: ‘now’) Not Before Time
hrhlist of headers to hashyesA ‘;’ (semicolon) delimited list of lowercase headers to include in the request hash calculation. At a minimum you must include ‘Host’ and ‘Authorization’
rqhrequest hashyesPlease refer to ‘3. Create Hash of the Canonical Request’ above.

Example Payload:

Signature

To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

Signature Creation Example

Public Key

To validate the signature Twilio needs the public key. This public key needs to be uploaded to Twilio.The public key must be:

Jwt Public Private Key

  • Algorithm: RSA
  • Modulus::bitLength: 2048
  • Format: X.509

Public key to successfully validate the Example JWT (below):

Private Key

The request has to be signed with a private key. The private key must match the public key uploaded to Twilio.

There are no limitations on the private key (as opposed to the public key, enumerated above) other than it needs to match the public key. It can be either PKCS#1 or PKCS#8 (whichever the signing library supports).

Private key used to sign the Example JWT:

Example JWT

The following JWT is composed of the example blocks from above. The JWT is signed with the private key above. This JWT can be validated with the public key above.

5. Attach JWT to the Request Header

The JTW needs to be added to the request via the Twilio-Client-Validation header.

Client Validation Java Example

The functionality is currently only supported in the latest Java helper library.

The following example covers all five steps of making a successful Client Validation request. This sample is also available on Github.

Notes:

Generate Public Private Key Pair For Jwt Jobs

Standard API Keys are not permitted to manage Accounts (e.g. create sub accounts) and other API Keys. If you require this functionality please refer to this page for additional details.

It may take a few minutes after Enforcing Public Key Client Validation from Settings for it to take effect.

Generate Public Private Key Pair For Jwt Mac

Need some help?

Jwt Private Key

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.