JWT (JSON Web Token) in PHP without using 3rd-party library. How to sign?
https://github.com/gradus0/appleAuth look method $appleAuthObj->get_jwt_token()
<?php
include_once "appleAuth.class.php";
// https://developer.apple.com/account/resources/identifiers/list/serviceId -- indificator value
$clientId = ""; // com.youdomen
// your developer account id -> https://developer.apple.com/account/#/membership/
$teamId = "";
// key value show in -> https://developer.apple.com/account/resources/authkeys/list
$key = "";
// your page url where this script
$redirect_uri = ""; // example: youdomen.com/appleAuth.class.php
// path your key file, download file this -> https://developer.apple.com/account/resources/authkeys/list
$keyPath =''; // example: ./AuthKey_key.p8
try{
$appleAuthObj = new \appleAuth\sign($clientId,$teamId,$key,$redirect_uri,$keyPath);
if(isset($_REQUEST['code'])){
$jwt_token = $appleAuthObj->get_jwt_token($_REQUEST['code']);
$response = $appleAuthObj->get_response($_REQUEST['code'],$jwt_token);
$result_token = $this->read_id_token($response['read_id_token']);
var_dump($response);
var_dump($result_token);
}else{
$state = bin2hex(random_bytes(5));
echo "<a href='".$appleAuthObj->get_url($state)."'>sign</a>";
}
} catch (\Exception $e) {
echo "error: ".$e->getMessage();
}
I solved it! I did not realize that the signature itself needs to be base64 encoded. In addition, I needed to set the last optional parameter of the hash_hmac
function to $raw_output=true
(see the docs. In short I needed to change my code from the original:
//build the signature
$key = 'secret';
$signature = hash_hmac('sha256',"$headers_encoded.$payload_encoded",$key);
//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature";
To the corrected:
//build the signature
$key = 'secret';
$signature = hash_hmac('sha256',"$headers_encoded.$payload_encoded",$key,true);
$signature_encoded = base64url_encode($signature);
//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature_encoded";
echo $token;
If you want to solve it using RS256 (instead of HS256 like OP) you can use it like this:
//build the headers
$headers = ['alg'=>'RS256','typ'=>'JWT'];
$headers_encoded = base64url_encode(json_encode($headers));
//build the payload
$payload = ['sub'=>'1234567890','name'=>'John Doe', 'admin'=>true];
$payload_encoded = base64url_encode(json_encode($payload));
//build the signature
$key = "-----BEGIN PRIVATE KEY----- ....";
openssl_sign("$headers_encoded.$payload_encoded", $signature, $key, 'sha256WithRSAEncryption');
$signature_encoded = base64url_encode($signature);
//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature_encoded";
echo $token;
Took me way longer than I'd like to admit