J'essaie de vérifier le code que j'ai obtenu du service "Se connecter avec Apple" sur mon Uri de redirection. J'ai utilisé les informations de la documentation pour créer les données de publication et générer le "client_secret".
La réponse que je reçois est: {"error":"invalid_client"}
.
Mes fonctions pour générer le "client_secret" se trouvent ci-dessous:
function encode($data) {
$encoded = strtr(base64_encode($data), '+/', '-_');
return rtrim($encoded, '=');
}
function generateJWT($kid, $iss, $sub, $key) {
$header = [
'alg' => 'ES256',
'kid' => $kid
];
$body = [
'iss' => $iss,
'iat' => time(),
'exp' => time() + 3600,
'aud' => 'https://appleid.Apple.com',
'sub' => $sub
];
$privKey = openssl_pkey_get_private($key);
if (!$privKey) return false;
$payload = encode(json_encode($header)).'.'.encode(json_encode($body));
$signature = '';
$success = openssl_sign($payloads, $signature, $privKey, OPENSSL_ALGO_SHA256);
if (!$success) return false;
return $payload.'.'.encode($signature);
}
Mes variables dans cet exemple:
$ kid est mon identifiant pour ma clé privée. Dans cet exemple, c'est JYJ5GS7N9K. J'ai obtenu l'identifiant d'ici https://developer.Apple.com/account/resources/authkeys/list
$ iss est l'identifiant d'équipe de mon compte développeur. Dans cet exemple, c'est WGL33ABCD6.
$ sub est la même valeur que "client_id". Mon "client_id" dans cet exemple est "dev.hanashi.sign-in-with-Apple". J'ai obtenu l'ID client des identifiants d'application ici: https://developer.Apple.com/account/resources/identifiers/list
$ key est ma clé privée générée par le compte développeur. La clé a un format comme celui-ci:
-----BEGIN PRIVATE KEY-----
myrandomgeneratedkeybyappledeveloperaccount
-----END PRIVATE KEY-----
Voici le code php pour faire la demande:
$key = <<<EOD
-----BEGIN PRIVATE KEY-----
myrandomgeneratedkeybyappledeveloperaccount
-----END PRIVATE KEY-----
EOD; // replaced with correct key
$kid = 'JYJ5GS7N9K'; // identifier for private key
$iss = 'WGL33ABCD6'; // team identifier
$sub = 'dev.hanashi.sign-in-with-Apple'; // my app id
$jwt = generateJWT($kid, $iss, $sub, $key);
$data = [
'client_id' => $sub,
'client_secret' => $jwt,
'code' => $_POST['code'],
'grant_type' => 'authorization_code',
'request_uri' => 'https://myurl.tld/redirect.php'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://appleid.Apple.com/auth/token');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6');
$serverOutput = curl_exec($ch);
curl_close ($ch);
echo $serverOutput;
Je reçois maintenant la réponse {"error":"invalid_client"}
depuis le serveur Apple. Qu'est-ce que je fais mal? Est-ce que je ne peux pas générer le jeton JWT?
Le {"error":"invalid_client"}
le message peut être lié à une signature non valide générée par la fonction openssl_sign. L'algorithme ES256 doit être utilisé pour signer le JWT et la signature générée doit être la concaténation de deux entiers non signés, notés R et S. Il s'avère que la fonction openssl_sign génère une signature ASN.1 codée DER qui n'est pas correcte pour Apple (voir ici ).
La solution consiste donc à convertir la signature ASN.1 codée DER générée par openSSL en une simple concaténation des valeurs R et S.
Cela peut être fait en utilisant la fonction suivante:
/**
* @param string $der
* @param int $partLength
*
* @return string
*/
public static function fromDER(string $der, int $partLength)
{
$hex = unpack('H*', $der)[1];
if ('30' !== mb_substr($hex, 0, 2, '8bit')) { // SEQUENCE
throw new \RuntimeException();
}
if ('81' === mb_substr($hex, 2, 2, '8bit')) { // LENGTH > 128
$hex = mb_substr($hex, 6, null, '8bit');
} else {
$hex = mb_substr($hex, 4, null, '8bit');
}
if ('02' !== mb_substr($hex, 0, 2, '8bit')) { // INTEGER
throw new \RuntimeException();
}
$Rl = hexdec(mb_substr($hex, 2, 2, '8bit'));
$R = self::retrievePositiveInteger(mb_substr($hex, 4, $Rl * 2, '8bit'));
$R = str_pad($R, $partLength, '0', STR_PAD_LEFT);
$hex = mb_substr($hex, 4 + $Rl * 2, null, '8bit');
if ('02' !== mb_substr($hex, 0, 2, '8bit')) { // INTEGER
throw new \RuntimeException();
}
$Sl = hexdec(mb_substr($hex, 2, 2, '8bit'));
$S = self::retrievePositiveInteger(mb_substr($hex, 4, $Sl * 2, '8bit'));
$S = str_pad($S, $partLength, '0', STR_PAD_LEFT);
return pack('H*', $R.$S);
}
/**
* @param string $data
*
* @return string
*/
private static function preparePositiveInteger(string $data)
{
if (mb_substr($data, 0, 2, '8bit') > '7f') {
return '00'.$data;
}
while ('00' === mb_substr($data, 0, 2, '8bit') && mb_substr($data, 2, 2, '8bit') <= '7f') {
$data = mb_substr($data, 2, null, '8bit');
}
return $data;
}
/**
* @param string $data
*
* @return string
*/
private static function retrievePositiveInteger(string $data)
{
while ('00' === mb_substr($data, 0, 2, '8bit') && mb_substr($data, 2, 2, '8bit') > '7f') {
$data = mb_substr($data, 2, null, '8bit');
}
return $data;
}
qui peut être trouvé dans la bibliothèque this . Plus de détails ici Connexion Apple, signez JWT pour l'authentification en utilisant PHP et openSSL
J'ai eu cette erreur plusieurs fois. Voici les causes que j'ai pu trouver:
invalid_client
les erreurs.Lorsque j'ai résolu ces problèmes, j'ai commencé à obtenir invalid_grant
Erreur. Voici les étapes que j'avais faites:
https://appleid.Apple.com/auth/authorize?response_type=code&state=abcdefg&client_id=com.company.Apple-sign-in-abcd&scope=openid&redirect_uri=https://app.com/redirect_uri
manuellement sur le navigateur Web,code
copié, j'ai POSÉ le https://appleid.Apple.com/auth/token
point de terminaison avec arguments x-www-form-urlencoded: Si vous perdez quelques secondes, code
est invalidé et vous obtiendrez invalid_grant
Erreur. Si vous copiez et collez immédiatement en quelques secondes, vous obtiendrez votre réponse:
{
"access_token": "abcdefg",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "abcdefg",
"id_token": "abcdefghijklmnopqrstu"
}
La prochaine étape serait de décoder id_token avec la clé publique d'Apple.
J'ai fait un petit paquet pour générer Apple secret client en php, basé sur jwt-framework: https://github.com/kissdigital-com/Apple-sign-in- client-secret-generator