Why does openssl_verify() fail to verify my JWT token signature?

2.4k views Asked by At

The code:

$token = $request->getQueryParams();
$jwt_access_token = $token['access_token'];

$separator = '.';

list($header, $payload, $signature) = explode($separator, $jwt_access_token);

$decoded_signature = base64_decode($signature);

$payload_to_verify = utf8_decode($header . $separator . $payload);

$public_key = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/pubkey.pem');

$verified = openssl_verify($payload_to_verify, $decoded_signature, $public_key, OPENSSL_ALGO_SHA256);

Example access token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6IjU0YmEzYmQwZDRkYzAxYmZhNmJjYjdjYTIwOTQwY2YzY2NmM2EyNjQiLCJqdGkiOiI1NGJhM2JkMGQ0ZGMwMWJmYTZiY2I3Y2EyMDk0MGNmM2NjZjNhMjY0IiwiaXNzIjoiIiwiYXVkIjoidGVzdGNsaWVudCIsInN1YiI6InNhbGxlIiwiZXhwIjoxNDgyMTIyODY4LCJpYXQiOjE0ODIxMTkyNjgsInRva2VuX3R5cGUiOiJiZWFyZXIiLCJzY29wZSI6bnVsbH0.q-xwz16YbUiaDzdeiNBoaeZIYNx8G6HXLZRMJjpiezotq0nICTokVxuf3OUur6433MhT6wVCUENUeuJfuvLg3wKZWHfXSoTMG77Gkv1Wart6hlIPFqyZ13gyTzquaKRRDoRD9WSBcKXfTF6V59cWHrwAM5nRIQeOzBdYXZPwnV-9RhXUpjUhJ0LKRJsDZ5EwJUFsIDb7oZ70b3uLJqa79h42Dc5mQWj75uIo8mVCmH9N1BPJRn-Hb9ttgpu2oRgDOqsm4zdBz2CfSkPiHa-j6qKEWHocyLQBZ8XLxyvFSAFVIwqv4OVCBHanzbkfY-ZKkKh1THeyiIcrB9ed6vwzRg

Public Key:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs3k2ZkpYqCX94B+qC2yc
4atWx+C5d7kFQAgBrbv5gfFuIST0DLt5lvv0OZZI57+ydNXb2G/jyOJPH3ll2mHS
Z+PKAo9aQoL5iYIjz+yYp2Im51LBh4e0Kt1RSjuy4M5RI1JVSsM9rt3NoLMzehv8
57g+uv1T177cJabDvKeqWdD0qR4N7PE/nV0Hrumz5kP4EnYhN0A2wjbXyyyllxhL
nr3Wqii0XJxBF3AwLUlqP1NYhm2wYq0CTjQrgv3/9WCvr4fSzBitzQAP6ZIFRHO3
F8EIaK6r6cDiP2ABmtTrmPAj3ZpqGVBPnvY9yVrqUS0pMxjvvesJiPd2jGrjLQFN
LQIDAQAB
-----END PUBLIC KEY-----

I can't get the openssl_verify() function to return 1. It always returns 0 (it can't verify the token). I don't understand why. Can anyone please point me in the right direction?

1

There are 1 answers

2
Spomky-Labs On BEST ANSWER

It fails because the JWS parts are not Base64 encoded, but Base64 Url Safe encoded.

The error comes from the line

$decoded_signature = base64_decode($signature);

It should be

$decoded_signature = base64_decode(strtr($signature, '-_', '+/'));


Note 1: the trailing = can be removed (use the function trim) and have no impact on the decoding function.

Note 2: this verification only works with RSA-based signature. EC-based signatures require additional steps. This may explain the failing cases reported by other users in comments of this page.