FILTER BY TAG

JWT Validation Keys

Unified Click to Pay
uses JWTs to transfer data. These
Unified Click to Pay
integration elements are JWTs:
  • The capture context that is returned by the
    /uctp/v1/sessions
    request. You must verify this JWT immediately on your server to ensure that the SDK script URL, PAN encryption keys, and session configuration have not been tampered with.
    For information about
    /uctp/v1/sessions
    requests, see Generate Unified Click to Pay Capture Context in the
    Cybersource
    API Reference.
  • The response that is returned by
    checkout()
    . You must verify this JWT on your server after you receive it from the client.
Each JWT must be validated before you trust its contents.
IMPORTANT
The header of each JWT header contains a key ID field (
kid
) that references the specific RSA public key that
Cybersource
used to sign that token. The integrator must retrieve this public key from
Cybersource
and use it to verify the JWT's signature. If the signature is invalid, the JWT must be rejected.
JWT validation keys are composed of these elements located in the JWT header:
  • kid
    : Key ID that references the RSA public key that signed the JWT. Each JWT may have a different
    kid
    .
  • alg
    : The signing algorithm. This is often
    RS256
    (RSA with SHA-256).
You can retrieve the RSA public key as a JSON Web Key from these endpoints:
  • Test
    : GET
    https://apitest.cybersource.com
    /flex/v2/public-keys/{kid}
  • Production
    : GET
    https://api.cybersource.com
    /flex/v2/public-keys/{kid}
IMPORTANT
You can store RSA public keys, however,
Cybersource
recommends that you use the keys from the URL. This ensures that you use the most current key.

JavaScript Example: JWT Signature Authentication

async function verifyJwt(token) { const [headerB64, payloadB64, signatureB64] = token.split('.'); const header = JSON.parse(base64UrlDecode(headerB64)); // Fetch the public key using the kid from the JWT header const response = await fetch(`https://${API_HOST}/flex/v2/public-keys/${header.kid}`, { headers: generateSignatureHeaders('GET', `/flex/v2/public-keys/${header.kid}`, null) }); const jwk = await response.json(); const publicKey = crypto.createPublicKey({ key: jwk, format: 'jwk' }); // Verify the signature const signedData = `${headerB64}.${payloadB64}`; const signatureBuffer = base64UrlDecode(signatureB64); const valid = crypto.verify('RSA-SHA256', Buffer.from(signedData), publicKey, signatureBuffer); if (!valid) throw new Error('JWT signature verification failed'); return { header, payload: JSON.parse(base64UrlDecode(payloadB64)), signature: signatureB64, raw: token }; }