5

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' => '[email protected]',
    '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.

3
  • php.net/manual/en/function.openssl-sign.php Commented Apr 29, 2021 at 22:48
  • 3
    @M.SallarRabiei it doesn't make much sense to suggest the same question as duplicate target that the OP mentioned in his post. Obviously he read it already and it did not answer his question. Commented Apr 30, 2021 at 7:30
  • 1
    and generally the linked question seems to be a sort of XY-problem with the conclusion "it doesn't make sense to use a asymmetric private key for HMAC" in the answer, but not really a solution for this question here. Commented Apr 30, 2021 at 7:45

3 Answers 3

5

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";
Sign up to request clarification or add additional context in comments.

Comments

1

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.

2 Comments

the question title says that OP wants RS256 and the recommended way IMO is to use a proper JWT library
The third party requires RS256 so I cannot use HS256
0

You can generate JWT in PHP using RSA256

function base64url_encode($data){
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function generateToken(){
    $privateKey = file_get_contents('private.pem');

    $base64UrlHeader = base64url_encode(
        json_encode(
            array(
                'typ' => 'JWT',
                'alg' => 'RS256'
            )
        )
    );

    $now = time();
    $base64UrlPayload = base64url_encode(
        json_encode(
            array(
                "sub" => "1",
                "exp" => $now + 3600,
                "iat" => $now
            )
        )
    );

    openssl_sign(
        $base64UrlHeader.".".$base64UrlPayload,
        $RSA256,
        $privateKey,
        "sha256WithRSAEncryption"
    );

    $keyRSA256 = base64url_encode($RSA256);
    $jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $keyRSA256;

    return json_encode(array('status' => true, 'code' => 200, 'data' => $jwt));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.