Skip to content

Instantly share code, notes, and snippets.

@gaffling
Last active January 21, 2021 08:45
Show Gist options
  • Save gaffling/6395c40aa706da3e0a9f63b47d6b7857 to your computer and use it in GitHub Desktop.
Save gaffling/6395c40aa706da3e0a9f63b47d6b7857 to your computer and use it in GitHub Desktop.
[Token Class] Simple PHP JSON Web Token (JWT) #php #class #jwt
<?php
/**
* JWT (JSON Web Token) Implementation
*
* Minimum implementation used by Realtime auth, based on this:
*
* READ https://codeofaninja.com/2018/09/rest-api-authentication-example-php-jwt-tutorial.html
* INFO http://self-issued.info/docs/draft-jones-json-web-token-01.html
* CODE https://github.com/luciferous/jwt
* DOCU https://github.com/zxsleebu/jwt
* TEST https://jwt.io/
*
* @author Neuman Vong <neuman@twilio.com>
* @see CRYPT <http://phpclasses.org/blog/package/11662/post/1-php-encrypt-and-decrypt-sensitive-data.html>
*/
class JWT {
/**
* @param string $token The token
* @param string|null $key The secret key
* @param bool $crypt Use crypt
* @param bool $verify If false the verification processs is skipped
*
* @return string The data as an array
*/
public static function decode($token, $key = null, $crypt = true, $verify = true) /* ENTSCHLÜSSELN */
{
// Also encrypt the data with the same key
if ($crypt === true) $token = JWT::decrypt($key, $token);
$bad = 0;
$token_segments = explode('.', $token);
if (count($token_segments) != 3) {
$bad = 1;
} else { // vanGato
list($head_b64, $data_b64, $crypto_b64) = $token_segments;
if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($head_b64)))) {
$bad = 1;
}
if (null === $data = JWT::jsonDecode(JWT::urlsafeB64Decode($data_b64))) {
$bad = 1;
}
$sig = JWT::urlsafeB64Decode($crypto_b64);
if ($verify) {
if (empty($header->alg)) {
$bad = 1;
}
if ($sig != JWT::sign("$head_b64.$data_b64", $key, $header->alg)) {
$bad = 1;
}
// vanGato - Let the token expire if $verify=true but no "exp" is set
if (!isset(json_decode(json_encode($data), true)["exp"])) {
$bad = 1;
} else if (null !== ($expire = json_decode(json_encode($data), true)["exp"])) {
if ($expire < time()){
$bad = 1;
}
}
}
}
if (!$bad) {
return json_decode(json_encode($data), true);
}
}
/**
* @param object|array $data The data as an array
* @param string $key The secret key
* @param bool $crypt Use crypt
* @param string $algo The signing algorithm
*
* @return string The token
*/
public static function encode($data, $key, $crypt = true, $algo = 'HS256') /* VERSCHLÜSSELN */
{
$header = array('typ' => 'JWT', 'alg' => $algo);
$segments = array();
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($data));
$signing_input = implode('.', $segments);
$signature = JWT::sign($signing_input, $key, $algo);
$segments[] = JWT::urlsafeB64Encode($signature);
$return = implode('.', $segments);
// Also encrypt the data with the same key
if ($crypt === true) $return = JWT::encrypt($key, $return);
return $return;
}
/**
* @param string $data The data to sign
* @param string $key The secret key
* @param string $method The signing algorithm
*
* @return string An encrypted message
*/
public static function sign($data, $key, $method = 'HS256')
{
$methods = array(
'HS256' => 'sha256',
'HS384' => 'sha384',
'HS512' => 'sha512',
);
if (empty($methods[$method])) {
// error
}
if (!empty($methods[$method])) {
return hash_hmac($methods[$method], $data, $key, true); // true = return RAW binary
}
}
/**
* @param string $input JSON string
*
* @return object Object representation of JSON string
*/
public static function jsonDecode($input)
{
$obj = json_decode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
}
else if ($obj === null && $input !== 'null') {
// error
}
return $obj;
}
/**
* @param object|array $input A PHP object or array
*
* @return string JSON representation of the PHP object or array
*/
public static function jsonEncode($input)
{
$json = json_encode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
JWT::handleJsonError($errno);
}
else if ($json === 'null' && $input !== null) {
// error
}
return $json;
}
/**
* @param string $input A base64 encoded string
*
* @return string A decoded string
*/
public static function urlsafeB64Decode($input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
/**
* @param string $input Anything really
*
* @return string The base64 encode of what you passed in
*/
public static function urlsafeB64Encode($input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
/**
* @param int $err_no An error number from json_last_error()
*
* @return void
*/
private static function handleJsonError($err_no)
{
$messages = array(
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
);
// vanGato
if (isset($messages[$err_no])) {
die($messages[$err_no]);
} else {
die('Unknown JSON error: ' . $err_no);
}
}
/**
* vanGato
* @param string $key The secret key
* @param string $string_to_encrypt The string data to encrypt
* @param string $type The return type base64 or hex (default: base64)
*
* @return string The encrypted string
*/
private static function encrypt($key, $string_to_encrypt, $type='base64')
{
$key = md5($key);
// mcrypt_encrypt() DEPRECATED as of PHP 7.1.0 and REMOVED as of PHP 7.2.0
$rtn = openssl_encrypt($string_to_encrypt, 'bf-ecb', $key, true);
if (strtolower($type)=='base64') {
$rtn = base64_encode($rtn);
$rtn = rtrim($rtn, '=');
} else {
$rtn = bin2hex($rtn);
}
return($rtn);
}
/**
* vanGato
* @param string $key The secret key
* @param string $string_to_encrypt The string data to decrypt
* @param string $type The input type base64 or hex (default: base64)
*
* @return string The decrypted string
*/
private static function decrypt($key, $string_to_decrypt, $type='base64')
{
$key = md5($key);
if (strtolower($type)=='base64') {
$string_to_decrypt = base64_decode($string_to_decrypt);
} else {
$string_to_decrypt = hex2bin($string_to_decrypt);
}
// mcrypt_decrypt() DEPRECATED as of PHP 7.1.0 and REMOVED as of PHP 7.2.0
$rtn = openssl_decrypt($string_to_decrypt, 'bf-ecb', $key, true);
return($rtn);
}
}
<?php
/* -------------------------------------------------------------- */
/* [Token Class] Simple PHP JSON Web Token (JWT) #php #class #jwt */
/* -------------------------------------------------------------- */
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
$root = dirname(__FILE__);
require_once $root . '/JWT.php';
unset($root);
$prefix = '<hr size="1"><pre><b>';
$suffix = PHP_EOL . PHP_EOL . '</pre>';
$data = array(
"exp" => 91608212663, // Expiration date in Unix time format
"name" => "John Doe", // Other data
);
$token = JWT::encode($data, 'my_key');
echo $prefix . 'SET DATA</b><br>'; var_dump($data); echo $suffix;
echo $prefix . 'TOKEN</b><br>' . $token . $suffix;
echo $prefix . 'GET DATA</b><br>'; var_dump(JWT::decode($token, 'my_key')); echo $suffix;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment