How to create a valid JWT in PHP using RSA256

Viewed 1197

I have been having similar difficulties to this question. I need to create a JWT in php. I have the following code:

define('RSA_PRIVATE', 'MIICXAIB......EWxOf9o=');

$payload = json_encode([
    'sub' => 'username',
    'email' => 'john@example.com',
    'given_name' => 'John',
    'family_name' => 'Example',
    'iat' => time(),
    'nonce' => '12345'
]);


$header = json_encode([
    'typ' => 'JWT',
    'alg' => 'RS256'
]);

$base64UrlHeader = base64UrlEncode($header);
$base64UrlPayload = base64UrlEncode($payload);
$signature = hash_hmac('sha256', "$base64UrlHeader.$base64UrlPayload", RSA_PRIVATE, true);                                

$base64UrlSignature = base64UrlEncode($signature);
$jwt = "$base64UrlHeader.$base64UrlPayload.$base64UrlSignature";

echo($jwt);


function base64UrlEncode($text)
{
    return str_replace(
        ['+', '/', '='],
        ['-', '_', ''],
        base64_encode($text)
    );
}

Whenever I attempt to validate with the third party that needs my JWT it comes back with a message telling me

Signature validation failed: rsa signature did not match

When I attempt to validate using the JWT debugger, it too says it is invalid.

Am I missing something here? Like the previous question I have only ever seen examples where people are using small secrets and not private RSA keys.

2 Answers

Following the answer by @Michal Trojanowski I went on to use openssl_sign. However this did not work when I had the key as a variable in my code. Instead, following the example on the php manual I managed to get it to work using the following adjustment:

$private_key = openssl_pkey_get_private("file:///path.to/jwtRS256.key");

openssl_sign(
    "$base64UrlHeader.$base64UrlPayload",
    $signature,
    $private_key,
    "sha256WithRSAEncryption"
);

openssl_free_key($private_key);

$base64UrlSignature = zd_base64UrlEncode($signature);
$jwt = "$base64UrlHeader.$base64UrlPayload.$base64UrlSignature";

You chose RS256 as the signature algorithm, which is an asymmetrical signing algorithm and you create the signature with a HMAC function, which is a symmetrical signing algorithm.

If you want to stick to RS256 try to follow this answer: https://stackoverflow.com/a/43313973/1712294

If you want to stick with a symmetrical algorithm change the data in your header to

$header = json_encode([
    'typ' => 'JWT',
    'alg' => 'HS256'
]);

The recommended way is to go with an asymmetrical algorithm.

Related