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-stringsHeader
, the second part is the Base64url-encoded JSON-stringsPayload
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, wherebySHA256withRSA
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 thebase64_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.