Search code examples
phpjsonjwtbase64base64url

Correct way to generate JWTs


I am new to JWTs so I used an article that told me to generate JWT like this:

// Create token header as a JSON string
    $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
    
    // Create token payload as a JSON string
    $payload = json_encode(['userId' => $userId, 'exp' => time()+60*60*24*30]);

    // Encode Header to Base64Url String
    $base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));

    // Encode Payload to Base64Url String
    $base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
 
    // Create Signature Hash
    $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, 'mySecret', true);

    // Encode Signature to Base64Url String
    $base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

    // Create JWT
    $jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;

I was wondering if the str_replace is necessary because I think it is messing with the verification of the JWTs?

Thanks.


Solution

  • It's correct and necessary, unless you can directly base64url encode, because it changes the encoding from base64 to base64url, which is the encoding format that JWT uses.

    Base64 and Base64Url encoding are almost identical, there are just 2 characters, '+' and '/' that need to be replaced by '-' and '_' and the padding that is deleted from the string. The str_replace is exactly doing that.

    The content of the signature is not affected by this, and it's just the decoded value that is relevant for verificaton.

    Regarding the general question about the "correct way": technically your way is correct and good for educational purposes. It's good to know how things work. For any real life application there are many libraries which can do the job for you.