For Developers

JWKS

The JSON Web Key Set (JWKS) endpoint provides the public keys necessary to verify the signatures of JSON Web Tokens (JWTs) issued by the OpenID Connect (OIDC) provider. These keys are used to ensure the integrity and authenticity of the tokens.

Endpoint Details

In the provided configuration, the JWKS endpoint is:

"jwks_uri": "https://ed.link/api/authentication/oidc/jwks"

Example Response

The JWKS endpoint returns a JSON object containing an array of keys. Here is an example response:

{
    "keys": [
        {
            "kty": "RSA",
            "kid": "b376bb7a-c7bd-4e12-a1f1-e17e9466e06e",
            "use": "sig",
            "alg": "RS256",
            "e": "AQAB",
            "n": "0_MkNlMYVPFrPlOtXp_2ePMXOx4UHRsZPJI_RcaWHjsP-Rwjbuj5HGdemvajq7WFWZfofXjG9lHsgz45rguDXeyEvyk2aNm55nHp-Ul6OWnrYEpfb3mlDTZojA3kpNZydW2R33qpSl5d9Oq34EW-K61H5mHDl2lcftgRtRs0qtA2HONfAvb2ROrO78ZalvLPd5rAdCeyOYyUQLfzgDBwtZxrQbBhOKPrpBn6ssvCV0K3XzK9pD4Z2VZuwQl3e8U6OUDjTEQ3c5XovhV0aoS_qDxsiyM6rCDir1SuqzTEgcKoD6Fgglf1EZz4y_kbo4lWcwuQ4k03_yvxKHkj4aplIQ"
        }
    ]
}

Key Fields Explained

  • kty: The key type. In this case, it is "RSA".
  • kid: The key identifier. This is used to match the key against the kid in the JWT header.
  • use: The intended use of the key. Here, "sig" indicates the key is used for signature verification.
  • alg: The algorithm used with the key. "RS256" indicates the RSA SHA-256 algorithm.
  • e: The exponent for the RSA key.
  • n: The modulus for the RSA key.

How to Use the JWKS Endpoint

1. Retrieve the Public Keys

To verify the signature of a JWT, your application first needs to retrieve the public keys from the JWKS endpoint. Here is an example using axios in Node.js:

const axios = require('axios');

async function getJWKS() {
    const jwksResponse = await axios.get('https://ed.link/api/authentication/oidc/jwks');
    return jwksResponse.data;
}

// Example usage
getJWKS()
    .then((jwks) => {
        console.log(jwks);
    })
    .catch((error) => {
        console.error(error);
    });

2. Parse the JWT Header

Extract the kid (Key ID) from the JWT header. This is used to select the appropriate key from the JWKS.

3. Select the Appropriate Key

Using the kid from the JWT header, find the corresponding key in the JWKS. Here’s an example of how you might do this:

function getKeyByKid(jwks, kid) {
    return jwks.keys.find((key) => key.kid === kid);
}

// Example usage
const kid = 'b376bb7a-c7bd-4e12-a1f1-e17e9466e06e'; // This would come from the JWT header
getJWKS()
    .then((jwks) => {
        const key = getKeyByKid(jwks, kid);
        console.log(key);
    })
    .catch((error) => {
        console.error(error);
    });

4. Verify the JWT Signature

Using the selected key, verify the JWT’s signature. This typically involves converting the key components (n and e) into a usable format and using a library that supports JWT verification.

Here’s an example using the jsonwebtoken library in Node.js:

const jwt = require('jsonwebtoken');

async function verifyJWT(token) {
    const jwks = await getJWKS();
    const decodedHeader = jwt.decode(token, { complete: true }).header;
    const key = getKeyByKid(jwks, decodedHeader.kid);

    if (!key) {
        throw new Error('Key not found');
    }

    // Convert JWKS to PEM format
    const publicKey = jwkToPem(key);

    // Verify the token
    jwt.verify(token, publicKey, { algorithms: ['RS256'] }, (err, decoded) => {
        if (err) {
            console.error('Invalid token', err);
        } else {
            console.log('Token is valid', decoded);
        }
    });
}

// Example usage
const token = 'YOUR_JWT_TOKEN';
verifyJWT(token).catch((error) => {
    console.error(error);
});

function jwkToPem(key) {
    const jwk = {
        kty: key.kty,
        n: key.n,
        e: key.e
    };
    return jwkToPem(jwk);
}

Replace YOUR_JWT_TOKEN with the actual token you want to verify.

Conclusion

Using the JWKS endpoint involves retrieving the public keys, selecting the appropriate key based on the kid in the JWT header, and then using that key to verify the JWT’s signature. This ensures the integrity and authenticity of the JWTs used in your application.