Reputation: 11
I have a PHP application and I am trying to generate a token to authenticate users so that they can access Firebase from the browser.
I have generated a private key from service account in Firebase console and I use the firebase/php-jwt library. When trying to access with the signInWithCustomToken
method from javascript I always get the error>
The custom token format is incorrect. Please see the documentation
The code with which I generate the token is:
use Firebase\JWT\JWT;
require_once("php-jwt-master/src/JWT.php");
$service_account_email = "[email protected]"; // Dots are app name
$key = "-----BEGIN PRIVATE KEY-----\n..........\n-----END PRIVATE KEY-----\n"; // Dots are private key from the downloaded file
$time = time();
$token = array( 'iat' => $time,
'exp' => $time + 3000,
'uid' => '1',
'aud' => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
'iss' => $service_account_email,
'sub' => $service_account_email
);
$jwt = JWT::encode($token, $key, 'HS256');
The javascript code is:
function login(){
var token = document.getElementById("token").value;
firebase.auth().signInWithCustomToken(token)
.then((user) => {
console.log("Autenticado");
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode + " - " + errorMessage);
});
}
I have checked the jwt with jwt.io tool and it seems to be correct.
I am not sure in the key format, I have tried with the header and the "\ n" in a single line as in the file and also without the "\ n" and using the returns in a multiline variable with "<<<".
I have also tried using the encode function with or without the parameter 'HS256'. But I always get the same error.
Thanks in advance for any response.
Upvotes: 1
Views: 2316
Reputation: 11
Solved, changing the name of the algorith from HS256 to RS256!. Thanks.
Upvotes: 0
Reputation: 855
I can understand why this might be a little confusing as some of the documentation and code contradict each other. Even the firebase/php-jwt/src/JWT.php
file mentions that HS256
is a supported algorithm.
class JWT
. . .
public static $supported_algs = array(
'ES256' => array('openssl', 'SHA256'),
'HS256' => array('hash_hmac', 'SHA256'),
'HS384' => array('hash_hmac', 'SHA384'),
'HS512' => array('hash_hmac', 'SHA512'),
'RS256' => array('openssl', 'SHA256'),
'RS384' => array('openssl', 'SHA384'),
'RS512' => array('openssl', 'SHA512'),
);
However, according to the Google OAuth 2.0 documentation, it mentions explicitly that:
The only signing algorithm supported by the Google OAuth 2.0 Authorization Server is RSA using SHA-256 hashing algorithm. This is expressed as
RS256
in the alg field in the JWT header.
I tested this on my Linux machine by following these documents:
I installed all of the requirements:
$ sudo apt update -y && sudo apt upgrade -y
$ sudo apt install php libapache2-mod-php
$ sudo systemctl start apache2
$ sudo apt install php-cli unzip
$ curl -sS https://getcomposer.org/installer -o composer-setup.php
$ HASH=`curl -sS https://composer.github.io/installer.sig`
$ php -r "if (hash_file('SHA384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
$ composer require firebase/php-jwt
I created a jwt-auth.php
file:
<?php
// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;
require __DIR__ . '/vendor/autoload.php';
// Get your service account's email address and private key from the JSON key file
$service_account_email = "firebase-adminsdk-<REDACTED>@<REDACTED>.iam.gserviceaccount.com";
$privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC8kGa . . . <REDACTED> . . .
B2zNzvrlgRmgBrklMTrMYgm1NPcW+bRLGcwgW2PTvNM=
-----END RSA PRIVATE KEY-----
EOD;
$publicKey = <<<EOD
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3D . . . <REDACTED> . . .
ehde/zUxo6UvS7UrBQIDAQAB
-----END PUBLIC KEY-----
EOD;
$now_seconds = time();
$payload = array(
"iss" => $service_account_email,
"sub" => $service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => "1"
);
$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo "Encode:\n" . print_r($jwt, true) . "\n";
$decoded = JWT::decode($jwt, $publicKey, array('RS256'));
/*
NOTE: This will now be an object instead of an associative array. To get
an associative array, you will need to cast it as such:
*/
$decoded_array = (array) $decoded;
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
?>
Ran:
$ php jwt-auth.php
And I was able to authenticate:
Encode:
eyJ0eXAiOiJKV1QiL . . . <REDACTED> . . .ZnverW8YFTaC_ZVFnI
Decode:
Array
(
[iss] => firebase-adminsdk-<REDACTED>@<REDACTED>.iam.gserviceaccount.com
[sub] => firebase-adminsdk-<REDACTED>@<REDACTED>.iam.gserviceaccount.com
[aud] => https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit
[iat] => 1618406214
[exp] => 1618409814
[uid] => 1
)
Upvotes: 2