Skip to content
Advertisement

Understanding RS256 and SHA256 during JWT Token creation

I am creating a JWT Token using a private key in PHP. For this I am using the OpenSSL library. Before anything I will share my code :

PHP

    $header = [
        self::ALG => self::RS256,
        self::TYP => self::JWT
    ];
    $payload = [
        "iss" => $this->getClientID(),
        "iat" => time(),
        "exp" => time()+999
    ];
    $header = base64_encode(json_encode($header));
    $payload = base64_encode(json_encode($payload));
    $token = $header.".".$payload;
    $pkey = openssl_pkey_get_private($this->getPrivateKey(), $this->getPassPhrase());
    openssl_sign($token, $signature, $pkey, 'sha256'); //no algorithm specifically for rs256
    $sign = base64_encode($signature);
    return $token.".".$sign;

So, this JWT Token will be used for authentication in a server which I am trying to hit. But I get the response from the external server as a Bad Request, problem happening in my JWT token creation.

With same credentials, I tried in javascript using the library jsrsasign and it then gives me the correct response.

JAVASCRIPT

// Header
var oHeader = { alg: 'RS256', typ: 'JWT' };
// Payload
var oPayload = {};
var tNow = rs.KJUR.jws.IntDate.get('now');
var tEnd = tNow + 1000;
oPayload.iss = "playground.pizza";
oPayload.iat = tNow;
oPayload.exp = tEnd;
var sHeader = JSON.stringify(oHeader);
var sPayload = JSON.stringify(oPayload);
var pkey = "my private key" //I replaced all the new line with n here and had in one line
var prvKey = rs.KEYUTIL.getKey(pkey, "my_pass_phrase");
var sJWT = rs.KJUR.jws.JWS.sign("RS256", sHeader, sPayload, prvKey);
ultraSecureToken = sJWT;

One difference which I can clearly see is that for the signature generation function in the php end I am passing sha256 as the algorithm and in the JavaScript RS256 is passed.

I read about how sha256 is just a hashing algorithm and RS256 is used for encoding, but in all the libraries I found in php, they were internally passing sha256 only in the openssl_sign function. And openssl_sign doesn’t have RS256 as an algorithm parameter.

So, firstly is there anywhere where I went wrong.

Secondly, is there a way we can generate a signature using RS256 in php.

PS : I am looking for solution in php.

Advertisement

Answer

  • The return-value of KJUR.jws.JWS.sign consists of three portions separated by a dot. The first part is the Base64url-encoded JSON-string sHeader, the second part is the Base64url-encoded JSON-string sPayload and the third part is the Base64url-encoded signature. The data to be signed consist of the first two portions including the dot separating the two portions. RS256 means that SHA256 and RSA with RSASSA-PKCS1-v1_5 padding is used for the signature. This can also be easily verified online, e.g. here, whereby SHA256withRSA is to be selected as the algorithm.

  • openssl_sign also uses RSA with RSASSA-PKCS1-v1_5 padding and therefore creates the same signature with SHA256, assuming the same key and the same data to be signed are applied.

  • jsrsasign uses Base64 url-encoding (RFC4648, sect. 5), while PHP (or more precisely the base64_encode-method) uses standard Base64-encoding (RFC4648, sect. 4), which most likely is one cause of the issue. This means that the encoding in the current PHP-code must be changed to Base64url, e.g. here.

  • Of course, the underlying JSON-strings in the PHP-code ($header, $payload and $token) must also be identical to their counterparts in the JavaScript-code, otherwise the signature will differ. Since the PHP-code is incomplete, this cannot be checked and could be another cause of the problem.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement