Why is JWT::decode() returning { "status": "\"kid\" empty, unable to lookup correct key" }
Asked Answered
V

1

25

My first ever Stack Overflow Question - here it goes!

I've encoded a Firebase JWT token to authenticate a 'buyer' in my PHP Slim API. It encodes correctly and generates a JWT token in Postman,

Postman JWT encoding

but when I try to use the JWT for Bearer Authentication to access a group of protected routes in my routes.php file, I receive:

{ "status": "\"kid\" empty, unable to lookup correct key" }

Here's my generateJWT() function: - in Buyer.php class.

public static function generateJWT($id) 
    {
        $buyer = $buyer =  self::findOrFail($id);
        if (!$buyer) {
            return false;
        }
        $key = self::JWT_KEY;
        $expiration = time() + self::JWT_EXPIRE;
        $issuer = 'Lab03_I425.com';
        $token = [
            'iss' => $issuer,
            'exp' => $expiration,
            'isa' => time(),
            'data' => [
                'uid' => $id,
                'name' => $buyer->username,
                'email' => $buyer->email] ];
        return JWT::encode (
            $token,
            $key,
            'HS256',
        );
    }

And here's my validateJWT() function: - - - - in Buyer.php class

public static function validateJWT($token)
    {
        return JWT::decode($token, self::JWT_KEY,  array('HS256') );
    }

I am aware there is a JWT parameter $kid that exists beyond the $payload, $key, $alg params, but I was under the impression it is not necessary to complete authentication. I'm new to using Slim, Tokens, and Web Services so any help would be greatly appreciated.

Here's the authJWT method in my BuyerController.php that is called in routes.php:

public function authJWT(Request $request, Response $response)
    {
        $params = $request->getParsedBody();
        $username = $params['username'];
        $password = $params['user_password'];
        $authBuyer = Buyer::authenticateBuyer($username, $password);
        if ($authBuyer) {
            $status_code = 200;
            $jwt = Buyer::generateJWT($authBuyer->id);
            $results = [
                'status' => 'login successful',
                'jwt' => $jwt,
                'name' => $authBuyer->username
            ];
        } else {
            $status_code = 401;
            $results = [
                'status' => 'login failed',
            ];
        }
        //return $results;
        return $response->withJson($results, $status_code,
            JSON_PRETTY_PRINT);
    }

I looked in the - - - - - vendor\firebase\php-jwt\src\JWT.php - - - - file and noticed

if (empty($kid)) {
    throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
}

If I understand correctly, this value can be a string or null, and apparently mine is empty (a string of 0 length) if its returning the aboe UnexpectedValueException().

Why is this? and how can I change this so my JWT middleware allows me to access my grouped routes?

Thank you in advance for your feedback and guidance.

Vitale answered 17/5, 2022 at 17:3 Comment(3)
Well I seem to have figure out a solution, for anyone else who might be dealing with a similar issue, in my validateJWT method - I changed from returning a JWT::decode() to JWT::urlsafeB64Decode() and was able to access the necessary routes.Vitale
It looks like an encoding issue. Make sure your client sends the token in the Authorization header correctly encoded.Sucre
@Vitale remember that you can answer your own question and accept the answer. This will help other users as the question will be marked as resolved.Mescal
W
70

I faced the same problem, but reading the github for firebase package I saw that they changed the decode process.

Now you need to create an instance of the Key class, and use it when calling the decode method, like:

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$data = JWT::decode($token, new Key($topSecret, 'HS256'));

Using that way fixes my problem and decoding is working now. The version of the package is 6.2.0. Check if you are using that version or greater.

Warlike answered 19/5, 2022 at 20:20 Comment(4)
Thank you for this, you saved me hours of debugging. I also informed some other package mantainers to let them know that google has broken them.Suppletion
Google keeps changing stuff and breaking backwards compatibility with no respect of users. I find it extremely rude of them.Suppletion
this error happened because different version of laravel passportPlantain
Really appreciate this Ans! I have been trying for more than a day, and none of the references give an exact solution. Thanks.Brahmani

© 2022 - 2024 — McMap. All rights reserved.