Search code examples
phpoauth-2.0

JWT Computing the Signature SHA256withRSA


I'm trying to

Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the API console. The output will be a byte array.

so let's take Header and Claim set and put them into array

{"alg":"RS256","typ":"JWT"}.
{
  "iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope":"https://www.googleapis.com/auth/prediction",
  "aud":"https://accounts.google.com/o/oauth2/token",
  "exp":1328554385,
  "iat":1328550785
}

just like Service Account: Computing the Signature

JSON Web Signature (JWS) is the specification that guides the mechanics of generating the signature for the JWT. The input for the signature is the byte array of the following content:

{Base64url encoded header}.{Base64url encoded claim set}

so I build array just to test that

  $seg0 = array(
    "alg" => "RS256",
    "typ" => "JWT"
  );
  $seg1 = array(
    "iss" => "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
    "scope" => "https://www.googleapis.com/auth/prediction",
    "aud" => "https://accounts.google.com/o/oauth2/token",
    "exp" => 1328554385,
    "iat" => 1328550785
  );

  $segs = array(
    json_encode($seg0),
    stripslashes(json_encode($seg1))
  );
  $segments = array(
    rtrim(strtr(base64_encode($segs[0]), '+/', '-_'), '='),
    rtrim(strtr(base64_encode($segs[1]), '+/', '-_'), '='),
  );

Here it is. THe first 2 arrays encode successful.

Output
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ

I go forward and encode the signature

The signature must then be Base64url encoded. The signature is then concatenated with a ‘.’ character to the end of the Base64url representation of the input string. The result is the JWT. It should be the following:
{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

  $signature = makeSignedJwt($segments);
  //$signature = makeSignedJwt($segs);
  echo $signature .'<br /><br />';
  $segments[] = rtrim(strtr(base64_encode($signature), '+/', '-_'), '=');
  echo '<pre>'; print_r($segments); echo '</pre>';  

function makeSignedJwt($segments)
{
    $data = implode('.', $segments);
    if (!openssl_sign($data, $signature, privateKey, "sha256"))
    {
        exit("Unable to sign data");
    }
    return $signature;
}

Output
    Array
(
    [0] => eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
    [1] => eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ
    [2] => xFS6iZdJku5RKJ5_XdH3W5A8e9V3wsaFeQhAXoJtuxzW-xvqZq1CdEJJAo60VvK1UFONElVf_pthezEyz-eyWsoRGVZFibUQBaKXLI8eR28eFlaCAKH7bKh820uR7IwuRx4xr8MPmnC8so9u9TEY153gkU6Mz9e--pQPlcLlGY
)

Must be missing something..


Solution

  • I'm not sure what your question is, but the following worked for me:

    //helper function
    function base64url_encode($data) { 
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 
    }
    
    //Google's Documentation of Creating a JWT: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests
    
    //{Base64url encoded JSON header}
    $jwtHeader = base64url_encode(json_encode(array(
        "alg" => "RS256",
        "typ" => "JWT"
    )));
    //{Base64url encoded JSON claim set}
    $now = time();
    $jwtClaim = base64url_encode(json_encode(array(
        "iss" => "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
        "scope" => "https://www.googleapis.com/auth/prediction",
        "aud" => "https://www.googleapis.com/oauth2/v4/token",
        "exp" => $now + 3600,
        "iat" => $now
    )));
    //The base string for the signature: {Base64url encoded JSON header}.{Base64url encoded JSON claim set}
    openssl_sign(
        $jwtHeader.".".$jwtClaim,
        $jwtSig,
        $your_private_key_from_google_api_console,
        "sha256WithRSAEncryption"
    );
    $jwtSig = base64url_encode($jwtSig);
    
    //{Base64url encoded JSON header}.{Base64url encoded JSON claim set}.{Base64url encoded signature}
    $jwtAssertion = $jwtHeader.".".$jwtClaim.".".$jwtSig;