Build a REST API in PHP with JWT Authentication

Build a REST API in PHP with JWT Authentication

Build a REST API in PHP with JWT Authentication

This project demonstrates how to build a stateless REST API from scratch in PHP using JSON Web Tokens for authentication.

Features

  • JWT-based stateless authentication
  • CRUD endpoints for a resource (tasks)
  • PDO with prepared statements (SQL injection safe)
  • Consistent JSON response envelope
  • Input validation and sanitisation

Step 1 — Install JWT Library

composer require firebase/php-jwt

Step 2 — JWT Helper

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));
    }
}

Step 3 — Auth Middleware

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);
    }
}

Step 4 — Task Endpoints

// 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