Created
August 27, 2024 05:56
-
-
Save grittyninja/edb1cf6fefff5288bdedbfceb250ede8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// JWT implementation with SQLite in PHP supporting RS256, HS256, and none | |
// Initialize SQLite database | |
$db = new SQLite3('users.db'); | |
// Create users table if not exists | |
$db->exec('CREATE TABLE IF NOT EXISTS users ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
username TEXT UNIQUE, | |
password TEXT, | |
email TEXT | |
)'); | |
// Insert sample user data | |
$db->exec("INSERT OR IGNORE INTO users (username, password, email) VALUES | |
('user1', '" . password_hash('password1', PASSWORD_DEFAULT) . "', '[email protected]'), | |
('user2', '" . password_hash('password2', PASSWORD_DEFAULT) . "', '[email protected]')"); | |
// JWT Secret Key for HS256 (in a real-world scenario, this should be stored securely) | |
$jwt_secret = 'your_secret_key_here'; | |
// RSA keys for RS256 (in a real-world scenario, these should be stored securely) | |
$private_key = <<<EOD | |
-----BEGIN RSA PRIVATE KEY----- | |
MIICXAIBAAKBgQC8kGa1pSjbSYZVebtTRBLxBz5H4i2p/llLCrEeQhta5kaQu/Rn | |
vuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t0tyazyZ8JXw+KgXTxldMPEL9 | |
5+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4ehde/zUxo6UvS7UrBQIDAQAB | |
AoGAb/MXV46XxCFRxNuB8LyAtmLDgi/xRnTAlMHjSACddwkyKem8//8eZtw9fzxz | |
bWZ/1/doQOuHBGYZU8aDzzj59FZ78dyzNFoF91hbvZKkg+6wGyd/LrGVEB+Xre0J | |
Nil0GReM2AHDNZUYRv+HYJPIOrB0CRczLQsgFJ8K6aAD6F0CQQDzbpjYdx10qgK1 | |
cP59UHiHjPZYC0loEsk7s+hUmT3QHerAQJMZWC11Qrn2N+ybwwNblDKv+s5qgMQ5 | |
5tNoQ9IfAkEAxkyffU6ythpg/H0Ixe1I2rd0GbF05biIzO/i77Det3n4YsJVlDck | |
ZkcvY3SK2iRIL4c9yY6hlIhs+K9wXTtGWwJBAO9Dskl48mO7woPR9uD22jDpNSwe | |
k90OMepTjzSvlhjbfuPN1IdhqvSJTDychRwn1kIJ7LQZgQ8fVz9OCFZ/6qMCQGOb | |
qaGwHmUK6xzpUbbacnYrIM6nLSkXgOAwv7XXCojvY614ILTK3iXiLBOxPu5Eu13k | |
eUz9sHyD6vkgZzjtxXECQAkp4Xerf5TGfQXGXhxIX52yH+N2LtujCdkQZjXAsGdm | |
B2zNzvrlgRmgBrklMTrMYgm1NPcW+bRLGcwgW2PTvNM= | |
-----END RSA PRIVATE KEY----- | |
EOD; | |
$public_key = <<<EOD | |
-----BEGIN PUBLIC KEY----- | |
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kGa1pSjbSYZVebtTRBLxBz5H | |
4i2p/llLCrEeQhta5kaQu/RnvuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t | |
0tyazyZ8JXw+KgXTxldMPEL95+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4 | |
ehde/zUxo6UvS7UrBQIDAQAB | |
-----END PUBLIC KEY----- | |
EOD; | |
// Function to generate JWT | |
function generateJWT($user_id, $username, $alg = 'HS256', $exp = 3600) { | |
global $jwt_secret, $private_key; | |
$header = [ | |
'typ' => 'JWT', | |
'alg' => $alg | |
]; | |
$payload = [ | |
'user_id' => $user_id, | |
'username' => $username, | |
'exp' => time() + $exp | |
]; | |
$base64_header = base64_encode(json_encode($header)); | |
$base64_payload = base64_encode(json_encode($payload)); | |
$signature = ''; | |
switch ($alg) { | |
case 'HS256': | |
$signature = hash_hmac('sha256', "$base64_header.$base64_payload", $jwt_secret, true); | |
break; | |
case 'RS256': | |
openssl_sign("$base64_header.$base64_payload", $signature, $private_key, OPENSSL_ALGO_SHA256); | |
break; | |
case 'none': | |
// No signature for 'none' algorithm | |
break; | |
} | |
$base64_signature = base64_encode($signature); | |
return "$base64_header.$base64_payload.$base64_signature"; | |
} | |
// Function to validate JWT | |
function validateJWT($token) { | |
global $jwt_secret, $public_key; | |
$parts = explode('.', $token); | |
if (count($parts) != 3) return false; | |
$header = json_decode(base64_decode($parts[0]), true); | |
$payload = json_decode(base64_decode($parts[1]), true); | |
$signature = base64_decode($parts[2]); | |
if ($payload['exp'] < time()) return false; | |
$base64_header = $parts[0]; | |
$base64_payload = $parts[1]; | |
switch ($header['alg']) { | |
case 'HS256': | |
$expected_signature = hash_hmac('sha256', "$base64_header.$base64_payload", $jwt_secret, true); | |
return hash_equals($expected_signature, $signature) ? $payload : false; | |
case 'RS256': | |
return openssl_verify("$base64_header.$base64_payload", $signature, $public_key, OPENSSL_ALGO_SHA256) === 1 ? $payload : false; | |
case 'none': | |
// Warning: 'none' algorithm is insecure and should not be used in production | |
return $payload; | |
default: | |
return false; | |
} | |
} | |
// Handle requests | |
$request_method = $_SERVER['REQUEST_METHOD']; | |
$request_uri = $_SERVER['REQUEST_URI']; | |
switch ($request_uri) { | |
case '/login': | |
if ($request_method === 'POST') { | |
$data = json_decode(file_get_contents('php://input'), true); | |
$username = $data['username'] ?? ''; | |
$password = $data['password'] ?? ''; | |
$alg = $data['alg'] ?? 'HS256'; | |
$stmt = $db->prepare('SELECT id, password FROM users WHERE username = :username'); | |
$stmt->bindValue(':username', $username, SQLITE3_TEXT); | |
$result = $stmt->execute(); | |
$user = $result->fetchArray(SQLITE3_ASSOC); | |
if ($user && password_verify($password, $user['password'])) { | |
$token = generateJWT($user['id'], $username, $alg); | |
echo json_encode(['token' => $token]); | |
} else { | |
http_response_code(401); | |
echo json_encode(['error' => 'Invalid credentials']); | |
} | |
} | |
break; | |
case '/refresh': | |
if ($request_method === 'POST') { | |
$headers = getallheaders(); | |
$token = $headers['Authorization'] ?? ''; | |
$token = str_replace('Bearer ', '', $token); | |
$payload = validateJWT($token); | |
if ($payload) { | |
$parts = explode('.', $token); | |
$header = json_decode(base64_decode($parts[0]), true); | |
$new_token = generateJWT($payload['user_id'], $payload['username'], $header['alg']); | |
echo json_encode(['token' => $new_token]); | |
} else { | |
http_response_code(401); | |
echo json_encode(['error' => 'Invalid token']); | |
} | |
} | |
break; | |
case '/user': | |
if ($request_method === 'GET') { | |
$headers = getallheaders(); | |
$token = $headers['Authorization'] ?? ''; | |
$token = str_replace('Bearer ', '', $token); | |
$payload = validateJWT($token); | |
if ($payload) { | |
$stmt = $db->prepare('SELECT id, username, email FROM users WHERE id = :id'); | |
$stmt->bindValue(':id', $payload['user_id'], SQLITE3_INTEGER); | |
$result = $stmt->execute(); | |
$user = $result->fetchArray(SQLITE3_ASSOC); | |
if ($user) { | |
echo json_encode($user); | |
} else { | |
http_response_code(404); | |
echo json_encode(['error' => 'User not found']); | |
} | |
} else { | |
http_response_code(401); | |
echo json_encode(['error' => 'Invalid token']); | |
} | |
} | |
break; | |
default: | |
http_response_code(404); | |
echo json_encode(['error' => 'Not found']); | |
break; | |
} | |
$db->close(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment