The JSON Web Key (JWK) standard defines a consistent way to represent a cryptographic key in a JSON structure. The JSON Web Key Set (JWKS) extension defines a consistent way to represent a set of cryptographic keys in a JSON structure. The JWKS standard is used as part of the OpenID Connect Discovery standard. An OpenID Connect Discovery document 1) defines a particular infrastructure, and 2) references a document which contains the JWKS definition of all the keys which are used for that particular infrastructure.

The JWKS document will have HTTP cache control headers returned along with the document contents. Client applications should always respect the cache control headers and never hard-code the values of the certificates and keys. Certificates are subject to change without prior notification to the client application developers.

JWKS Document Format and Contents

The format of JSON within the JWKS document is as follows:

{
"keys": [
    {
      "kty": "RSA",
       "use": "sig",
       "kid": "57cf50cdc6762aa3a5c01d326f45d73", 
      "n": "zUy8BsruXBWunO8JxXBcoyd2NXjsw-e5SnbIxijNHeTaHOGyckHh7QwXczDZonOfDdA1mhFjeH6JD7rMYymZqlNicx0zI5tEp0WPo2AiyPvY6XyxGAj3rPM0c94UtvaZs3m3kPKNWgIdkmtBVnR58OH75_RGvBoPTin6PJrIfrIOe_mctpwPmwmpqH23yVQZXffiL9LTLPgzLtS31j0Oh2Cia7AuZtjynGdtaV2x_ghnh8kJp6OgPVOF-NXVE2Ko-SHS3g_zpxDG94ig3Odvla00SX4rt-vZEHlvnNBXZQ4kXTFC2lQ7waf_U6LfolgOJAYKUuCrvF5T9VTr_ZCr-w",
      "e": "AQAB", 
      "x5c":
["MIIFrTCCBJWgAwIBAgIQBXz1DNxnYqo6XAHTJvRdczANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFNlcnZlciBDQTAeFw0xNTEyMDEwMDAwMDBaFw0xODEyMDQxMjAwMDBaMGkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMQ4wDAYDVQQHEwVQcm92bzEhMB8GA1UEChMYQnJpZ2hhbSBZb3VuZyBVbml2ZXJzaXR5MRgwFgYDVQQDEw93c28yLWlzLmJ5dS5lZHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNTLwGyu5cFa6c7wnFcFyjJ3Y1eOzD57lKdsjGKM0d5Noc4bJyQeHtDBdzMNmic58N0DWaEWN4fokPusxjKZmqU2JzHTMjm0SnRY+jYCLI+9jpfLEYCPes8zRz3hS29pmzebeQ8o1aAh2Sa0FWdHnw4fvn9Ea8Gg9OKfo8msh+sg57+Zy2nA+bCamofbfJVBld9+Iv0tMs+DMu1LfWPQ6HYKJrsC5m2PKcZ21pXbH+CGeHyQmno6A9U4X41dUTYqj5IdLeD/OnEMb3iKDc52+VrTRJfiu369kQeW+c0FdlDiRdMULaVDvBp/9Tot+iWA4kBgpS4Ku8XlP1VOv9kKv7AgMBAAGjggJIMIICRDAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM2WVkYqISuFlyOzAdBgNVHQ4EFgQU+60dYHVBUyn2tOTrtkAtkFbLTZUwegYDVR0RBHMwcYIPd3NvMi1pcy5ieXUuZWR1ghF3c28ycGlrbTEuYnl1LmVkdYIRd3NvMnBpa20yLmJ5dS5lZHWCEndzbzJzdGctaXMuYnl1LmVkdYIRd3NvMnNpa20xLmJ5dS5lZHWCEXdzbzJzaWttMi5ieXUuZWR1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWc1LmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWc1LmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAF++eBetH4d5jzV0k8rOHG95YOCdplTXdiUqGBuWfNiWciXvqMY6J/bBe4/901WDDt94To/WhvgwpxH5TmFZXX4B6jgKzk0Ja8+PwfW+Xi2PFw/F03QLXfA1ddhjslmSfjH23g+9PFkt0bj/1ocXtbyQ1pgbE8nLOxtmQEQvqVX0tB4l7DkLxYVXPgPwptxZ7kciZN2cgwkVmBWB0SYyWdK9CL7uI+Bo+1IweSxI/UJwECIGVsmqJjAEIIB4xcikeAdIRfsJ/gjsAZZqZMsVp3hY/P8ILA2vVy4P5Jm8EJHPxpL7k+xEcK5tOZIG+qkHjM1TCvPVX0vgd3DZlo1Os50="
      ]
    }
  ]
}

The JWKS structure consists of an array of JWK entries named "keys". Each JWK entry in our document has the following keys:

Key Contents
kty The key type for this key. BYU only uses RSA keys for our OpenID Connect implementation.
use The intended usage for the key. Our keys are intended for the signing of id_tokens and JWTs.
kid The unique identifier for the key. Will be unique within the file. By convention we are using the serial number of the key.
n The modulus (2048 bit) of the key - Base64URL encoded.
e The exponent of the key - Base64URL encoded
x5c The X509 certificate chain containing the key. This is the Base64 (not Base64URL) encoded version of the DER representation of the certificate. According to standard, the contents also correspond to the PEM encoding of the certificate without the '-----BEGIN CERTIFICATE-----' and '-----END CERTIFICATE-----' header and footer, and with the newline characters removed.

For a definition of all possible values see the JWK standard, along with the JSON Web Algorithms standard.

Using the JWK Contents To Validate Signatures

Which entry in the JWK to use for signature validation depends upon the toolkit in use. Most toolkits can use the the certificate contained in the x5c key. Some may require the actual modulus and exponent. This document will only deal with the x5c key.

There are two ways to use the value of the x5c key:

  1. Use the DER format - The Base64 decoded value of the x5c key is the DER format of the certificate. This format is a binary format and should be stored and used according to whatever manner is necessary for the language and cryptography toolkit in use.
  2. Reconstruct the PEM format of the certificate chain (see the standard for PEM encoding for more information).
    1. Extract the value of the x5c key.
    2. Insert a new line character (no carriage return for you Windows types) every 64 characters (optional for some toolkits)
    3. Insert the ''-----BEGIN CERTIFICATE-----' and '-----END CERTIFICATE-----' header and footer. Note - the format of the header and footer, including the number of dash '-' characters must match the standard.
    4. If your toolkit requires a public key instead of a certificate, you will have to find a utility method to do the conversion. This is a very standard operation and should be trivial in most languages.
    5. Use either the PEM encoded public key or certificate to validate the signature in question.

 

Get the DER format (Node.js):

var key = '{JWK Object}';

function getCertificate(key, index) {
	var obj = JSON.parse(key);
	var chain = obj.x5c;
	return chain[index];
}

function getDER(certificate) {
	var buffer = new Buffer(certificate, 'base64');
	return buffer.toString();
}

var certificate = getCertificate(key, 0);
var der = getDER(certificate);
console.log(der);

 

Reconstruct the PEM format (Node.js):

var key = '{JWK Object}';

function getCertificate(key, index) {
	var obj = JSON.parse(key);
	var chain = obj.x5c;
	return chain[index];
}

function insertNewlines(certificate) {
	for (var i = 64; i < certificate.length; i += 65) {
		certificate = certificate.slice(0, i) + '\n' + certificate.slice(i);
	}
	return certificate;
}

function addBoundaries(certificate) {
	return "-----BEGIN CERTIFICATE-----\n" + certificate + "\n-----END CERTIFICATE-----";
}

function getPEM(certificate) {
	certificate = insertNewlines(certificate);
	certificate = addBoundaries(certificate);
	return certificate;
}

var certificate = getCertificate(key, 0);
var pem = getPEM(certificate);
console.log(pem);