I found it surprisingly hard to generate valid JWT tokens per this documentation, and kept getting a 401 (“Provide a properly configured and signed bearer token, and make sure that it has not expired”).
The trick is to omit the “alg” value from the header – the documentation is wrong – and pass that header array to the function signing the token. Here’s a working code sample:
include('./vendor/autoload.php');
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// https://developer.apple.com/documentation/appstoreconnectapi/generating_tokens_for_api_requests
// https://github.com/firebase/php-jwt
// key, key_id and apple_issuer_id from https://appstoreconnect.apple.com/access/api
$apple_key_id = '';
// don't hard code this in production, obviously..
$apple_key = <<<EOD
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
EOD;
$apple_issuer_id = '';
// create jwt payload array
$payload_array = [
'iss' => $apple_issuer_id,
'aud' => 'appstoreconnect-v1',
'iat' => time(),
'exp' => (time()+(60*5))
];
// create jwt payload header
// note - no "alg" in the below, per https://developer.apple.com/forums/thread/117754
$payload_header = [
"kid" => "'.$apple_key_id.'",
"typ" => "JWT"
];
// pass the payload header as an option, per https://github.com/firebase/php-jwt/pull/53/files
$apple_jwt = JWT::encode($payload_array, $apple_key, 'ES256', $apple_key_id,$payload_header);
.. and the code is on Github, here.