Hay algunas bibliotecas para implementar JSON Web Tokens (JWT) en PHP, como php-jwt. Estoy escribiendo mi propia clase, muy pequeña y simple, pero no puedo entender por qué mi firma falla en la validación. aquí aunque he tratado de apegarme al estándar. Llevo horas intentándolo y estoy atascado. ¡Por favor ayuda!
mi codigo es sencillo
//build the headers
$headers = ['alg'=>'HS256','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 = 'secret';
$signature = hash_hmac('SHA256',"$headers_encoded.$payload_encoded",$key);
//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature";
echo $token;
El base64url_encode
función:
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
Mis encabezados y payload coinciden perfectamente con el sitio de validación JWT predeterminado, pero mi firma no coincide, por lo que mi token está marcado como no válido. Este estándar parece muy sencillo, entonces, ¿qué tiene de malo mi firma?
Jugo de escarabajo
¡Lo resolví! No me di cuenta de que la firma en sí debe estar codificada en base64. Además, necesitaba establecer el último parámetro opcional del hash_hmac
función a $raw_output=true
(ver los documentos. En resumen, necesitaba cambiar mi código del 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";
A lo corregido:
//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;
-
¿Funciona esto a través de redes y diferentes URL…? generando este token en el servidor HTTP y verificando en el servidor HTTPS. siempre falla..
– MSQ
13 de febrero de 2018 a las 12:26
Si quieres resolverlo usando RS256 (en lugar de HS256 como OP) puede usarlo así:
//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;
Me tomó mucho más tiempo del que me gustaría admitir
-
Resolví mi problema usando “openssl_sign()”. Cuando intento firmar usando hash_hmac, no puedo descifrar el valor de la clave correctamente. Pero ahora se resolvió usando base64url_encode y openssl_sign. Gracias @cristián
– Ganesha
12 de enero de 2022 a las 15:21
graduado
https://github.com/gradus0/appleAuth
método de búsqueda $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="https://stackoverflow.com/questions/33773477/".$appleAuthObj->get_url($state)."">sign</a>";
}
} catch (\Exception $e) {
echo "error: ".$e->getMessage();
}
-
Su respuesta podría mejorarse con información de apoyo adicional. Edite para agregar más detalles, como citas o documentación, para que otros puedan confirmar que su respuesta es correcta. Puede encontrar más información sobre cómo escribir buenas respuestas en el centro de ayuda.
– Comunidad
Bot2 de octubre de 2021 a las 8:07