29-Autenticación JWT en PHP: Explicación y Ejemplo

 

Autenticación JWT en PHP: Explicación y Ejemplo

¿Qué es JWT?

JWT (JSON Web Token) es un estándar abierto que permite transmitir información de forma segura entre partes como un objeto JSON. Es muy utilizado para autenticación y autorización en APIs.

¿Por qué usar JWT?

  • Sin estado (Stateless): El servidor no necesita almacenar sesiones

  • Seguro: Los tokens están firmados digitalmente

  • Portable: Funciona en múltiples dominios y aplicaciones

  • Extensible: Puedes incluir cualquier información en el payload

Estructura de un JWT

Un JWT tiene 3 partes separadas por puntos:

  • Header: Metadatos sobre el tipo de token y algoritmo

  • Payload: Los datos que quieres transmitir

  • Signature: Firma digital para verificar autenticidad

Ejemplo completo de login con JWT

1. Instalación de dependencias

bash
composer require firebase/php-jwt

2. Configuración inicial

php
<?php
require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// Configuración
$secret_key = "tu_clave_secreta_super_segura"; // Debe ser larga y segura
$algorithm = 'HS256';
$issuer = "tu_dominio.com";
$audience = "tu_app";
$token_expiration = 3600; // 1 hora en segundos
?>

3. Endpoint de Login

php
<?php
// login.php
require 'config.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Obtener datos del request
    $data = json_decode(file_get_contents("php://input"), true);
    
    $username = $data['username'] ?? '';
    $password = $data['password'] ?? '';
    
    // Validar credenciales (en un caso real, verificar contra base de datos)
    if ($username === 'admin' && $password === 'password123') {
        // Credenciales válidas - generar token
        
        $issued_at = time();
        $expiration_time = $issued_at + $token_expiration;
        
        $payload = array(
            "iss" => $issuer,        // Emisor
            "aud" => $audience,      // Audiencia
            "iat" => $issued_at,     // Tiempo de emisión
            "exp" => $expiration_time, // Tiempo de expiración
            "data" => array(         // Datos del usuario
                "user_id" => 1,
                "username" => $username,
                "role" => "admin"
            )
        );
        
        // Generar el token JWT
        $jwt = JWT::encode($payload, $secret_key, $algorithm);
        
        // Responder con el token
        http_response_code(200);
        echo json_encode(array(
            "message" => "Login exitoso",
            "token" => $jwt,
            "expires" => $expiration_time
        ));
        
    } else {
        // Credenciales inválidas
        http_response_code(401);
        echo json_encode(array("message" => "Credenciales inválidas"));
    }
} else {
    http_response_code(405);
    echo json_encode(array("message" => "Método no permitido"));
}
?>

4. Middleware para verificar el token

php
<?php
// auth_middleware.php
function verifyToken() {
    $headers = apache_request_headers();
    $auth_header = $headers['Authorization'] ?? $headers['authorization'] ?? '';
    
    if (empty($auth_header)) {
        http_response_code(401);
        echo json_encode(array("message" => "Token requerido"));
        exit;
    }
    
    // Extraer el token del header "Bearer {token}"
    $token = str_replace('Bearer ', '', $auth_header);
    
    try {
        global $secret_key, $algorithm;
        
        // Decodificar y verificar el token
        $decoded = JWT::decode($token, new Key($secret_key, $algorithm));
        
        // El token es válido, devolver los datos decodificados
        return $decoded;
        
    } catch (Exception $e) {
        http_response_code(401);
        echo json_encode(array(
            "message" => "Token inválido",
            "error" => $e->getMessage()
        ));
        exit;
    }
}
?>

5. Endpoint protegido

php
<?php
// protected.php
require 'config.php';
require 'auth_middleware.php';

// Verificar el token
$decoded_token = verifyToken();

// Si llegamos aquí, el token es válido
$user_data = $decoded_token->data;

// Responder con datos protegidos
http_response_code(200);
echo json_encode(array(
    "message" => "Acceso concedido",
    "user_data" => $user_data,
    "protected_data" => "Esta información es solo para usuarios autenticados"
));
?>

6. Logout (lado del cliente)

php
<?php
// logout.php
// Para logout, simplemente el cliente debe eliminar el token almacenado

http_response_code(200);
echo json_encode(array("message" => "Logout exitoso - elimina el token del cliente"));
?>

Cómo usar la API

1. Login (obtener token)

bash
curl -X POST http://tudominio.com/login.php \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"password123"}'

2. Acceder a endpoint protegido

bash
curl -X GET http://tudominio.com/protected.php \
  -H "Authorization: Bearer {tu_token_jwt}"

3. Logout (en el cliente)

Simplemente eliminar el token del almacenamiento local/sessionStorage.

Consideraciones de seguridad

  1. Clave secreta: Debe ser larga y compleja, almacenada de forma segura

  2. HTTPS: Siempre usar HTTPS en producción

  3. Expiración: Tokens con tiempo de vida corto

  4. Almacenamiento: Guardar tokens en HttpOnly cookies o localStorage seguro

  5. Refresh tokens: Implementar sistema de refresh tokens para renovación

Ventajas sobre sesiones tradicionales

  • Escalabilidad: No requiere almacenamiento en servidor

  • APIs RESTful: Ideal para arquitecturas stateless

  • Cross-domain: Funciona bien en aplicaciones con múltiples dominios

  • Mobile-friendly: Fácil implementación en apps móviles

Este ejemplo proporciona una base sólida para implementar autenticación JWT en tu API PHP

Comentarios

Entradas más populares de este blog

1-Autenticación JWT en PHP: Explicación y Ejemplo

8-JWT en 10 minutos - ¿Qué es JWT? ¿Para que sirve? ¿Cuando usarlo? ¿Cómo se usa?

2-JSON Web Tokens