How To Validate A Gigya id_token

Skip to end of metadata
Go to start of metadata

 

Description

This page outlines the steps required to validate a JWT id_token returned from the accounts.getJWT API using the Public key returned from accounts.getJWTPublicKey or from a Gigya OIDC OP (OpenID Connect Provider) using the OP's public key.

 

Preparation

Your server must have all necessary RSA / Crypt libraries installed.

For this document we are using phpseclib version 1.0 with PHP.

 

Validation

The id_token returned from Gigya is a valid JWT that consists of  3 parts. To validate the authenticity of the JWT you must compare the header + payload (parts 1 and 2) against the signature (part 3) using the originating site's public key (the site that contains the user whose data you are attempting to validate).

To get the current valid public key for that site when using accounts.getJWT, call accounts.getJWTPublicKey with that site's API key, otherwise, you must receive the key located in the OIDC OP's Metadata Configuration from your Gigya OP.

 

Public keys are subject to change without warning for security reasons. Recommended best practice is to check the keyid returned in the JWT header against the kid (Key ID) of the public key you have stored from accounts.getJWTPublicKey, or that you received from the OP, and if they do not match, you must update your public key using accounts.getJWTPublicKey or contacting the OP.

 

Steps

  • Receive a JWT from either the accounts.getJWT API or returned from your Gigya OIDC OP.
  • Split the JWT into it's 3 parts (which are separated with a period (".")).
  • Separate out the signature, part 3 of the JWT, and save it as keySignature.
  • Recombine the 1st and 2nd parts of the JWT, separating them with a period (".") and save as tokenData.
  • Retrieve or set the Modulus (n) and Exponent (e) of the Public Key. If validating a JWT returned from accounts.getJWT, you will use accounts.getJWTPublicKey; if validating a JWT received from a Gigya OIDC OP, you must get the public key from the OP directly. An example response from accounts.getJWTPublicKey follows:

    {
      "callId": "2a9f1ffc32894e6e9e8872c3b850570d",
      "errorCode": 0,
      "apiVersion": 2,
      "statusCode": 200,
      "statusReason": "OK",
      "time": "2017-05-21T14:55:07.783Z",
      "kty": "RSA",
      "n": "qoQah4MFGYedrbWwFc3UkC1hpZlnB2_E922yRJfHqpq2tTHL_NvjYmssVdJBgSKi36cptKqUJ0Phui9Z_kk8zMPrPfV16h0ZfBzKsvIy6_d7cWnn163BMz46kAHtZXqXhNuj19IZRCDfNoqVVxxCIYvbsgInbzZM82CB86iYPAS7piijYn1S6hueVHGAzQorOetZevKIAvbH3kJXZ4KdY6Ffz5SFDJBxC3bycN4q2JM1qnyD53vcc0MitxyIUF7a06iJb5_xXBiA-3xnTI0FU5hw_k6x-sdB5Rglx13_2aNzdWBSBAnxs1XXtZUt9_2RAUxP1XORkrBGlPg9D7cBtQ", // <<< This is the Modulus
      "e": "AQAB", // <<< This is the Exponent, and is case sensitive
      "alg": "RS256",
      "use": "sig",
      "kid": "REQ0MUQ5N0NCRTJEMzk3M0U1RkNDQ0U0Q0M1REFBRjhDMjdENUFBQg"
    }
  • Replace all occurrences of "-" with "+" and "_" with "/" in the JWT signature and the modulus of the Public Key, as well as then base64 decoding them. An example follows:

    $keySignature = str_replace(['-','_'], ['+','/'], $keySignature); // Where $keySignature is part 3 of the JWT
    $n = str_replace(['-','_'], ['+','/'], $n); // Modulus of Public Key
    $keySignature = base64_decode($keySignature);
    $n = base64_decode($n);
  • You can now verify the signature using the phpseclib library. An example Follows:

    $rsa = new Crypt_RSA();
    $rsa->loadKey([
        "n" => new Math_BigInteger($n, 256),
        "e" => new Math_BigInteger($e, 256)
    ]);
    
    $rsa->setHash("sha256");
    $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
    
    echo $rsa->verify($tokenData, $keySignature) ?
        "=> Valid Signature!" :
        "=> Invalid Signature!";

Demo Validator

Try our live demo validator utilizing the below PHP code examples on Gigya's Demo Site.

 

Example Code

There are several code examples below, as well as a working demo you may use as a starting point for your implementation.

 

Basic Implementation

<?php
include_once('./libs/phpseclib1.0.6/Crypt/RSA.php');

function sanitizeAndBase64Decode($str)
{
    $str = str_replace(['-','_'], ['+','/'], $str);
    return base64_decode($str);
}

$idToken = 'your id token'; // getJWT
$n = 'your public key modulus'; // getJWTPublicKey
$e = 'your public key exponent'; // getJWTPublicKey

$splitToken =  explode(".",$idToken);
$header = $splitToken[0];
$payload = $splitToken[1];
$signature = $splitToken[2];

$tokenData = $header . '.' . $payload; // first two parts concanated

// Format data
$signature = sanitizeAndBase64Decode($signature);
$n = sanitizeAndBase64Decode($n);
$e = sanitizeAndBase64Decode($e);
 
// Validate signature
$rsa = new Crypt_RSA();
$rsa->loadKey([
    'n' => new Math_BigInteger($n, 256),
    'e' => new Math_BigInteger($e, 256)
]);
 
$rsa->setHash('sha256');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
 
echo $rsa->verify($tokenData, $signature) ?
    '<span style="color: green; font-weight: bold; font-size: 20px;">  => Valid Signature!</span>' :
    '<span style="color: red; font-weight: bold; font-size: 20px;">  => Invalid Signature!</span>';
?>

 

 

Additional Information

accounts.getJWT

accounts.getJWTPublicKey

OpenID Provider Setup

 

 

 

  • No labels