1

I am trying to get the jwt token, but i am getting errors everytime with everything that i try. Below are th things that i have tried. I do get the jwt-token without the package but when i use the jwt.io to check the signature verification,it fails every time. With the package i get different errors like the private key cannot be coereced and sometimes invalid algorithm. Please correct me where i am messing it up.

  • Without php-Jwt
        $header = [
            'alg' => "RS384",
            'typ' => "JWT"
        ];

        $payload = [
            'iss' => 'my-client-id',
            'sub' => 'my-client-id',
            'aud' => "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token",
            'jti' =>  (string)strtotime(gmdate("Y-m-d H:i:s")),
            'exp' =>  strtotime(gmdate("Y-m-d H:i:s")) + 270,
        ];

       $privateKey = "my private Key"

        $headers_encoded = $this->base64url_encode(json_encode($header));
        $payload_encoded = $this->base64url_encode(json_encode($payload));

        

        $signature = hash_hmac('sha384', $headers_encoded.'.'.$payload_encoded, $privateKey, true);
        
        // Encode the signature as a base64url string
        $signature_encoded = $this->base64url_encode($signature);

        $jwt = $headers_encoded.'.'.$payload_encoded.'.'.$signature_encoded;

- With php-jwt

  1. installed the package composer require firebase/php-jwt --ignore-platform-req=ext-mongodb
  2. Used the required files in my controller
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
  1. Tried Encoding:
        $check = JWT::encode(
          $header,
          $payload,
          $privateKey,
          'RS384'
      );

i get different errors like the private key cannot be coereced and sometimes invalid algorithm. Please correct me where i am messing it up.

In simple words, this is what I am doing or trying to do. A generic form of my code:

<?php

// Load the private key from a file
$privateKey = file_get_contents('private.key');

// Set the header and payload for the JWT
$header = [
    'alg' => 'RS384',
    'typ' => 'JWT'
];

$payload = [
    'sub' => '1234567890',
    'name' => 'John Doe',
    'iat' => 1516239022
];

// Encode the header and payload as JSON strings
$headerEncoded = base64_encode(json_encode($header));
$payloadEncoded = base64_encode(json_encode($payload));

// Concatenate the header, payload, and secret to create the signature
$signature = hash_hmac('sha384', "$headerEncoded.$payloadEncoded", $privateKey, true);

// Encode the signature as a base64 string
$signatureEncoded = base64_encode($signature);

// Concatenate the header, payload, and signature to create the JWT
$jwt = "$headerEncoded.$payloadEncoded.$signatureEncoded";

echo $jwt;

I do get the jwt-signature but on https://jwt.io/ it shows unverified.

Progman
  • 16,827
  • 6
  • 33
  • 48
ternary
  • 41
  • 4
  • To verify a token on jwt.io, you have to provide the public key. A signature can't be verified without knowing the key. But in your case it would fail anyway, because in the header you added "alg":"RS384", which is RSA-SHA384, but later you sign it `hash_hmac('sha384',...` (HMAC-SHA384 or short "HS384"). So you either need to change the header or the actual algorithm. – jps Dec 17 '22 at 11:20
  • @jps i tried googling the correct way to write the RS384 algorithm in PHP, and the search came up with **sha384** – ternary Dec 17 '22 at 11:31
  • Again: a call to `hash_hmac('sha384'...` creates a HMAC-SHA384 signature, not RSA-SHA384. So there's a conflict between what you claim in the header ("RS384") and what you actually have ("HS384"). I would also not advise doing it manually, because of exactly this kind of problem. And in your first code, you don't get an error regarding the key, because `hash_hmac(...` does not require any specific key format. In the second case, which is the preferred way, you have to provide a valid RSA private key. A simple string is not a valid key for RSxxx. – jps Dec 18 '22 at 12:44
  • Thank you @jps for your time, i used the openssl_sign() instead of hash_mac() and it worked. – ternary Dec 18 '22 at 16:48

1 Answers1

2

Fixed

  • Use this instead of hash_mac():
openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA384);
  • Make sure if the key is stored in PHP variable, format the key like this:
$privateKey =  "------BEGIN PRIVATE KEY------\n".
"MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\n".
"MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\n".
.
.
.
"TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\n".
"dn/RsYEONbwQSjIfMPkvxF+8HQ==\n".
"------END PRIVATE KEY------";

enclose every line in Double quotes "" and add \n at end of every line.

P.J.Radadiya
  • 1,493
  • 1
  • 12
  • 21
ternary
  • 41
  • 4