This project demonstrates how to build a stateless REST API from scratch in PHP using JSON Web Tokens for authentication.
composer require firebase/php-jwt
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JwtHelper
{
private const SECRET = 'your-secret-key';
private const ALGO = 'HS256';
private const TTL = 3600; // 1 hour
public static function generate(int $userId): string
{
return JWT::encode([
'sub' => $userId,
'iat' => time(),
'exp' => time() + self::TTL,
], self::SECRET, self::ALGO);
}
public static function verify(string $token): object
{
return JWT::decode($token, new Key(self::SECRET, self::ALGO));
}
}
function authenticate(): int
{
$header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (! str_starts_with($header, 'Bearer ')) {
jsonResponse(['error' => 'Missing token'], 401);
}
try {
$payload = JwtHelper::verify(substr($header, 7));
return $payload->sub;
} catch (\Exception $e) {
jsonResponse(['error' => 'Invalid token'], 401);
}
}
// GET /tasks
case 'GET':
$userId = authenticate();
$stmt = $pdo->prepare('SELECT * FROM tasks WHERE user_id = ? ORDER BY created_at DESC');
$stmt->execute([$userId]);
jsonResponse($stmt->fetchAll(PDO::FETCH_ASSOC));
break;
// POST /tasks
case 'POST':
$userId = authenticate();
$data = json_decode(file_get_contents('php://input'), true);
$stmt = $pdo->prepare('INSERT INTO tasks (user_id, title, done) VALUES (?, ?, 0)');
$stmt->execute([$userId, htmlspecialchars($data['title'])]);
jsonResponse(['id' => $pdo->lastInsertId()], 201);
break;
All Comments