JWKS endpoint for signature validation in WSO2 Identity Server

Chanika Ruchini
Identity Beyond Borders
5 min readDec 19, 2022

Authentication and authorization are the two terms used most often in the security of web applications. Due to the drawbacks of traditional cookies-based authentication method which makes use of HTTP cookies to authenticate client requests and store session information on the server, JWT tokens were introduced.

Whenever you need to work with a content of a JWT we should verify the signature. In order to verify it you need a public key, which corresponds to the private key used by the Authorization Server to sign the JWT. In the testing environments, JWT can be validated easily as we have the access to keystore which store the public-private key pair. In the production environment there should be a mechanism to convey our public keys to the third party who is going to use the tokens. in order to address this JWKS endpoint was introduced and this simplifies greatly key management in your system.

In this article, I will outline what is JWKS endpoint and how we can validate our tokens from it. For clarity, this guide is structured into several sections.

So let’s get started!🍾 🎉

What are JWT and How does the JWT signature work?

JSON Web Tokens (JWT) consist on a security mechanism to transfer information between two parties by using JSON-format tokens that are self-signed.

JWT consists of three parts called header, payload and signature which are separated by (.) Therefore, a JWT typically looks like the following.

xxxxx.yyyyy.zzzzz

  1. Header : [Javascript Object Signing and Encryption (JOSE) Header] This consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.

2. Payload : This contains Identity Information(claims). Typically User and Authentication Context.

3. Signature : Used to identify the sender. Token signature is the result of taking the token payload and apply RS256 encryption using the private key of the RSA key pair.

All three parts of the JWT are BASE64 encoded, which makes the JWT URL-encoded, this means it can be shared between two or more parts using HTTP.

Base64URLencode(Header).Base64URLencode(body).Base64URLencode(signature)

The signature will have the following pseudo-code:

RSASHA256(Base64URLencode(Header).Base64URLencode(body), private key)

if you need more information regarding each of these attributes, you can look into jwt.io.

JSON Web Key(JWK) & JSON Web Key Set(JWKS)

A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data
structure that represents a cryptographic key.The members of the object represent properties of the key, including its value.

A JWK Set is simply JSON data structure that represents a set of JWKs.

There are attributes that are mandatory within JWK, regardless on the signing algorithm (formally known as JWA). Such attributes are:

  • kty (Key Type) Parameter. This attribute identifies the cryptographic algorithm family used with the key, such as “RSA” or “EC”. This attribute is required.
  • kid (Key ID) : This is the thumbprint of the certificate. kid parameter is used to identify a key, with the purpose to choose among a set of keys within a JWK Set during key rollover. kid parameter is utilized to lookup the appropriate public key, as it is also included in the JWT JOSE header.
  • use (Public Key Use) Parameter. This parameter identifies the intended use of the public key. The “use” parameter is employed to indicate whether a public key is used for encrypting data or verifying the signature on data. This attribute is optional, although encouraged.

Following values defined by this specification are:

1. sig (signature)

2. enc (encryption)

  • alg : Parameter identifies the algorithm intended for use with the key. eg in RSA, we can have RSA256 or RSA512

In addition to the above common parameters, there are some optional parameters decribed in the JWK specification. Following are some algorithm specific parameters. When working specifically with RSA public keys, the following attributes can be used to describe such type of key:

  • n Parameter is used to define the modulus for both the public and private keys. Its length, usually expressed in bits, is the key length.
  • e Parameter is used to define the RSA public exponent

JWKS endpoint

The JSON Web Key Set (JWKS) endpoint is a read-only endpoint. This url returns the Identity Server’s public key set in Json web key set format. This contains the signing key(s) the RP uses to validate signatures from the Identity Server.

Usage of JWKS

The main benefit of allowing JWKS endpoint configuration is its ability to handle key rotation by external identity providers. Configuring this endpoint would enable you to programmatically discover JSON web keys and allow the third party identity providers to publish new keys without having the overhead of notifying each and every client application. This allows smooth key rollover and integration.

JWKS endpoint of wso2 IS

WSO2 IS exposes a JWKS endpoint for each tenant, which is found at following URLS.

Endpoint URL for super tenant

URL Format : https://<IS_HOST>:<IS_HTTPS_PORT>/oauth2/jwks
Sample url : https://localhost:9443/oauth2/jwks

Endpoint URL for tenants

URL Format : https://<IS_HOST>:<IS_PORT>/t/<TENANT_DOMAIN>/oauth2/jwks
Sample url : https://localhost:9443/t/foo.com/oauth2/jwks

This endpoint will contain the JWK used to verify all IS-issued JWTs for the perticular tenant. In each endpoints, we can have multiple keysets correspond to,

  1. Different keys in the keystore

2. Different algorithm in the identity.xml

From the identity.xml we can configure different algorithms for the following JWTs.

  • Access token
  • Id token
  • User info token

Each algorithm have their own kid to identify the key set easily. Currently, we only support RSA based algorithms.

{
"keys":[
{
"kty":"RSA",
"x5t#S256":"TURKbE5qSXhOMkUxT0dabE9HVm1NR1F4T1RGbE16Qm1ObUZqWmpRMFkyWXdPR1kwTjJJMFl6RTRZelpqTmpSaFltUm1NbVEwT0RkaU5EaGpNR0V3TUE",
"e":"AQAB",
"use":"sig",
"kid":"MDJlNjIxN2E1OGZlOGVmMGQxOTFlMzBmNmFjZjQ0Y2YwOGY0N2I0YzE4YzZjNjRhYmRmMmQ0ODdiNDhjMGEwMA_RS256",
"x5c":[
"MIIDqTCCApGgAwIBAgIEYfEVSjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxDTALBgNVBAsMBFdTTzIxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMjAxMjYwOTMyNThaFw0yNDA0MzAwOTMyNThaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjENMAsGA1UECwwEV1NPMjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkdgncoCrz655Lq8pTdX07eoVBjdZDCUE6ueBd0D1hpJ0\/zE3x3Az6tlvzs98PsPuGzaQOMmuLa4qxNJ+OKxJmutDUlClpuvxuf+jyq4gCV5tEIILWRMBjlBEpJfWm63+VKKU4nvBWNJ7KfhWjl8+DUdNSh2pCDLpUObmb9Kquqc1x4BgttjN4rx\/P+3\/v+1jETXzIP1L44yHtpQNv0khYf4j\/aHjcEri9ykvpz1mtdacbrKK25N4V1HHRwDqZiJzOCCISXDuqB6wguY\/v4n0l1XtrEs7iCyfRFwNSKNrLqr23tR1CscmLfbH6ZLg5CYJTD+1uPSx0HMOB4Wv51PbWwIDAQABo2MwYTAUBgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFH0KQ3YTZJxTsNsPyrZOSFgXXhG+MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjALBgNVHQ8EBAMCBPAwDQYJKoZIhvcNAQELBQADggEBAFNJ34CIiIlCxmyp27+KA224LaHVtL5DucFK0P22FQ+QKkONiUwO70KoVFreBH1Smxu4ePWk6rMZFOM5oL8HXYg3twy+5eGcL3PQd7X5dwAqlVivzokoi6SDaA\/bIG6J\/O1U9Qd4XEVJdVuLqjk1+cp70ALt0X6B7sNLfjFcbz3jQULNnK8HNvqbn7zQuP10s8p5y2qVkPBA\/pjigRDsIWR6p78QESF+TaHFjxfcD6f9cnYie+yEHERtG8k8x5jLFe+odI1\/QGZP8Fy0oKT+E\/TJ1FBh4rB1FtKylqGeauPu89DnaJ9+kvpNQ94yFmEuhtDByvDijxAqvlin3TPIfy8="
],
"alg":"RS256",
"n":"kdgncoCrz655Lq8pTdX07eoVBjdZDCUE6ueBd0D1hpJ0_zE3x3Az6tlvzs98PsPuGzaQOMmuLa4qxNJ-OKxJmutDUlClpuvxuf-jyq4gCV5tEIILWRMBjlBEpJfWm63-VKKU4nvBWNJ7KfhWjl8-DUdNSh2pCDLpUObmb9Kquqc1x4BgttjN4rx_P-3_v-1jETXzIP1L44yHtpQNv0khYf4j_aHjcEri9ykvpz1mtdacbrKK25N4V1HHRwDqZiJzOCCISXDuqB6wguY_v4n0l1XtrEs7iCyfRFwNSKNrLqr23tR1CscmLfbH6ZLg5CYJTD-1uPSx0HMOB4Wv51PbWw"
}
]
}

This output is for using 1 key at keystore and RS256 as algorithm. No of keysets change according to the no keystores and alogorithms.

Thank you for reading!

Reference

--

--