Skip to content
Advertisement

PHP JWT (JSON Web Token) with RSA signature without library

Anyboby know some solution in PHP to using JWT (JSON Web Token) with RSA signature without library? I tried so hard to find solutions without library or without using composer. All the options that I found use some kind of library.

Advertisement

Answer

I made my own solution using other examples on the way. Below we have 3 use cases and the specific PHP codes to anyone that want to use:

  1. Create RSA private and public keys for sign JWT using openssl library.
  2. Create JWT token and sign using RSA private keys.
  3. Validate JWT’s signed token using RSA public keys.
  4. Example of inverted encryptation. Use public key encryptation => private key decryptation.

1 – Create RSA private and public keys for sign JWT using openssl library:

// ====================== OPENSSL KEY CREATE METHOD ==================

// URL of the source: https://8gwifi.org/docs/php-asym.jsp
// I tried all 3 types of keys, but only RSA type works.

$password = "password"; // Change it for what value you want

$config = array(  
    "digest_alg" => "sha512",  
    "private_key_bits" => 2048,  
    "private_key_type" => OPENSSL_KEYTYPE_RSA,
);  
 
// Create the keypair  
$res = openssl_pkey_new($config);  
// Get private key  
openssl_pkey_export($res, $privkey);  
// Get public key  
$pubkey = openssl_pkey_get_details($res);  
$pubkey = $pubkey["key"];  
  
echo "====PKCS1 RSA Key in Non Encrypted Format ====n";  
var_dump($privkey);  
echo "====PKCS1 RSA Key in Encrypted Format====n ";  
  
// Get private key in Encrypted Format  
openssl_pkey_export($res, $privkey,$password);  
// Get public key  
$pubkey = openssl_pkey_get_details($res);  
$pubkey = $pubkey["key"];  
var_dump($privkey);  
echo "RSA Public Key n ";  
var_dump($pubkey); 

2 – Create JWT token and sign using RSA private keys and 3 – Validate JWT’s signed token using RSA public keys:

// ====================== JWT WITH ENCRYPT AND DECRYPT ==================

// ===== Variables definition

$keyPrivatePassword = 'password';
$keyPrivatePath = "private.key";
$keyPublicPath = "public.key";
$cryptMaxCharsValue = 245; // There are char limitations on openssl_private_encrypt() and in the url below are explained how define this value based on openssl key format: https://www.php.net/manual/en/function.openssl-private-encrypt.php#119810

$debug = Array(
    'print-msgs' => true,
    'print-openssl-errors' => false,
    'print-openssl-crypt' => false,
    'print-key-details' => false,
);

// ##################### START DEFINITION OF JWT

// ===== Definition of header

$header = [
   'alg' => 'RSA',
   'typ' => 'JWT'
];

$header = json_encode($header);
$header = base64_encode($header);

// ===== Definition of payload

$payload = [
    'iss' => 'localhost', // The issuer of the token
    'sub' => 'test', // The subject of the token
    'aud' => 'private', // The audience of the token
    'exp' => '1300819380', // This will define the expiration in NumericDate value. The expiration MUST be after the current date/time.
    'data' => [ // Change it with use case data
        'name' => 'User',
        'email' => 'user@mail'
    ]
];

$payload = json_encode($payload);
$payload = base64_encode($payload);

// ===== START ENCRYPT SIGN JWT

$data = $header.".".$payload;

// ===== Print example header

if($debug['print-msgs']){
    echo "JWT CRYPT / DECRYPT EXAMPLEnn";
    echo "Value of header . payload: ".$data."n";
}

// ===== Open private path and return this in string format

$fp = fopen($keyPrivatePath,"r");
$keyPrivateString = fread($fp,8192);
fclose($fp);

// ===== Open private key string and return 'resourse'

if(isset($keyPrivatePassword)){
    $resPrivateKey = openssl_get_privatekey($keyPrivateString,$keyPrivatePassword);
} else {
    $resPrivateKey = openssl_get_privatekey($keyPrivateString);
}

// ===== If any openssl error occurs, print it

$openSSLError = false;
if($debug['print-openssl-errors']){
    while($msg = openssl_error_string()){
        echo $msg . "n";
        $openSSLError = true;
    }
}

// ===== See details of a private key

if($debug['print-key-details']){
    $keyPrivateDetails = openssl_pkey_get_details($resPrivateKey);

    echo "Private Key Details:n";
    echo print_r($keyPrivateDetails,true)."n";
}

// ===== Crypt data in parts if necessary. When char limit of data is upper than 'cryptMaxCharsValue'.

$rawDataSource = $data;

$countCrypt = 0;
$partialData = '';
$encodedData = '';
$split = str_split($rawDataSource , $cryptMaxCharsValue);
foreach($split as $part){
    openssl_private_encrypt($part, $partialData, $resPrivateKey);
    
    if($debug['print-openssl-crypt']){
        $countCrypt++;
        echo "CRYPT PART ".$countCrypt.": ".$partialData."n";
    }
    
    $encodedData .= (strlen($encodedData) > 0 ? '.':'') . base64_encode($partialData);
}

// ===== If any openssl error occurs, print it

$openSSLError = false;
if($debug['print-openssl-errors']){
    while($msg = openssl_error_string()){
        echo $msg . "n";
        $openSSLError = true;
    }
}

// ===== Print data encrypted

if($debug['print-msgs']){
    if($openSSLError) echo "n";

    echo "Encrypted signature: ".$encodedData."n";
}

// ===== Encode base64 again to remove dots (Dots are used in JWT syntaxe)

$encodedData = base64_encode($encodedData);

if($debug['print-msgs']){
    echo "Encrypted signature Base64: ".$encodedData."n";
}

$signature = $encodedData;

// ===== FINISH JWT

$JWTToken = $header.".".$payload.".".$signature;

if($debug['print-msgs']){
    echo "nJWT Token: ".$JWTToken."nn";
    echo "FINISH CREATE JWT!nn";
}

// ##################### START VALIDATE JWT

$token = $JWTToken;

$part = explode(".",$token);

$header = $part[0];
$payload = $part[1];
$signature = $part[2];

$encodedData = $signature;

// ===== Open public path and return this in string format

$fp = fopen($keyPublicPath,"r");
$chavePublicaString = fread($fp,8192);
fclose($fp);

// ===== Open public key string and return 'resourse'

$resPublicKey = openssl_get_publickey($chavePublicaString);

// ===== If any openssl error occurs, print it

$openSSLError = false;
if($debug['print-openssl-errors']){
    while($msg = openssl_error_string()){
        echo $msg . "n";
        $openSSLError = true;
    }
}

// ===== See details of a public key

if($debug['print-key-details']){
    $keyPublicDetails = openssl_pkey_get_details($resPublicKey);

    echo "Public Key Details:n";
    echo print_r($keyPublicDetails,true)."n";
}

// ===== Decode base64 to reaveal dots (Dots are used in JWT syntaxe)

$encodedData = base64_decode($encodedData);

if($debug['print-msgs']){
    echo "Encrypted signature: ".$encodedData."n";
}

// ===== Decrypt data in parts if necessary. Using dots as split separator.

$rawEncodedData = $encodedData;

$countCrypt = 0;
$partialDecodedData = '';
$decodedData = '';
$split2 = explode('.',$rawEncodedData);
foreach($split2 as $part2){
    $part2 = base64_decode($part2);
    
    if($debug['print-openssl-crypt']){
        $countCrypt++;
        echo "CRYPT PART ".$countCrypt.": ".$part2."n";
    }
    
    openssl_public_decrypt($part2, $partialDecodedData, $resPublicKey);
    $decodedData .= $partialDecodedData;
}

// ===== Print data decrypted

if($debug['print-msgs']){
    echo "Decrypted signature: ".$decodedData."n";
}

// ===== If any openssl error occurs, print it

$openSSLError = false;
if($debug['print-openssl-errors']){
    while($msg = openssl_error_string()){
        echo $msg . "n";
        $openSSLError = true;
    }
}

// ===== Validate JWT

if($debug['print-msgs']){
    echo "nFINISH VALIDATE JWT!nn";
}

if($header.".".$payload === $decodedData){
    echo "VALID JWT!nn";
    
    $payload = base64_decode($payload);
    $payload = json_decode($payload,true);
    
    echo "Payload:n";
    echo print_r($payload,true);
} else {
    echo "INVALID JWT!";
}

4 – Example of inverted encryptation. Use public key encryptation => private key decryptation:

// ====================== ENCRYPTATION INVERSE ==================
// If want to change Private Key Encryptation -> Public Key Decryptation to Public Key Encryptation -> Private Key Decryptation this example can help.

$keyPrivatePassword = 'password';
$keyPrivatePath = "private.key";
$keyPublicPath = "public.key";

// ===== Open private path and return this in string format

$fp = fopen($keyPrivatePath,"r");
$keyPrivateString = fread($fp,8192);
fclose($fp);

// ===== Open public path and return this in string format

$fp = fopen($keyPublicPath,"r");
$keyPublicString = fread($fp,8192);
fclose($fp);

// ===== Test of encryptation

$data = 'Data to encrypt';

$resPrivateKey = openssl_get_privatekey($keyPrivateString,$keyPrivatePassword);
$resPublicKey = openssl_get_publickey($keyPublicString);

echo 'Data: '.$data."n";

openssl_public_encrypt($data, $encData, $resPublicKey);

echo 'encData: '.$encData."n";

openssl_private_decrypt($encData, $decData, $resPrivateKey);

echo 'decData: '.$decData."n";
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement