Tokens JWT en PHP: Guía completa de autenticación y autorización

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Tokens JWT en PHP: Guía completa de implementación

\n\n

JWT (JSON Web Token) es un estándar abierto (RFC 7519) para la creación de tokens de acceso basados en formato JSON. En PHP, JWT se utiliza ampliamente para implementar autenticación sin estado (stateless authentication) en APIs REST, aplicaciones de una sola página (SPA) y microservicios.

\n\n

En este artículo, analizaremos en detalle cómo trabajar con tokens JWT en PHP: desde la instalación de la librería hasta la creación, verificación y renovación de tokens.

\n\n

¿Qué es JWT y por qué es necesario?

\n\n

JWT consta de tres partes separadas por puntos:

\n\n
    \n
  • Header (encabezado) — contiene el tipo de token (JWT) y el algoritmo de firma (por ejemplo, HS256 o RS256).
  • \n
  • Payload (carga útil) — contiene las declaraciones (claims): identificador de usuario, rol, hora de emisión (iat), fecha de vencimiento (exp) y otros datos.
  • \n
  • Signature (firma) — se crea mediante el hash del encabezado y la carga útil utilizando una clave secreta.
  • \n
\n\n

Principales ventajas de JWT:

\n
    \n
  • No requiere almacenar sesiones en el servidor (stateless).
  • \n
  • Puede contener cualquier dato (por ejemplo, el rol del usuario).
  • \n
  • Funciona con diferentes dominios y aplicaciones móviles.
  • \n
  • Se verifica fácilmente sin consultar la base de datos.
  • \n
\n\n

Instalación de la librería firebase/php-jwt

\n\n

Para trabajar con JWT en PHP, usaremos la librería popular firebase/php-jwt. La instalación se realiza a través de Composer:

\n\n
composer require firebase/php-jwt
\n\n

Después de la instalación, aparecerá la carga automática de Composer en el proyecto, que debe incluirse:

\n\n
require_once 'vendor/autoload.php';\n\nuse Firebase\\JWT\\JWT;\nuse Firebase\\JWT\\Key;
\n\n

Creación de un token JWT

\n\n

Para crear un token, es necesario definir una clave secreta ($secretKey) y formar el payload. Ejemplo:

\n\n
use Firebase\\JWT\\JWT;\n\n$secretKey = 'your-256-bit-secret-key-here';\n$issuedAt = time();\n$expirationTime = $issuedAt + 3600; // el token vive 1 hora\n\n$payload = [\n    'iss' => 'pythonlib.ru',        // emisor\n    'iat' => $issuedAt,             // hora de emisión\n    'exp' => $expirationTime,       // fecha de vencimiento\n    'sub' => 123,                   // identificador de usuario\n    'role' => 'admin'               // datos personalizados\n];\n\n$jwt = JWT::encode($payload, $secretKey, 'HS256');\necho $jwt;
\n\n

El resultado será una cadena como: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJweXRob25saWIucnUiLCJpYXQiOjE3Mjg0MDAwMDAsImV4cCI6MTcyODQwMzYwMCwic3ViIjoxMjMsInJvbGUiOiJhZG1pbiJ9.signature

\n\n

Verificación y decodificación de JWT

\n\n

Al recibir un token del cliente (por ejemplo, del encabezado Authorization: Bearer <token>), es necesario verificarlo:

\n\n
use Firebase\\JWT\\JWT;\nuse Firebase\\JWT\\Key;\n\n$secretKey = 'your-256-bit-secret-key-here';\n$jwt = $_SERVER['HTTP_AUTHORIZATION'] ?? '';\n\ntry {\n    $decoded = JWT::decode($jwt, new Key($secretKey, 'HS256'));\n    $userId = $decoded->sub;\n    $role = $decoded->role;\n    \n    echo "Usuario #{$userId} con rol {$role} autorizado.";\n} catch (\\Exception $e) {\n    http_response_code(401);\n    echo "Error: " . $e->getMessage();\n}
\n\n

Importante: la librería verifica automáticamente la fecha de vencimiento del token (exp) y la hora de emisión (iat). Si el token ha expirado o no es válido, se lanzará una excepción.

\n\n

Renovación de JWT (Refresh Token)

\n\n

Para aumentar la seguridad, los JWT suelen tener una vida corta (15–60 minutos). Para sesiones largas, se utiliza un Refresh Token, un token separado que se almacena en la base de datos y permite obtener un nuevo Access Token sin necesidad de volver a ingresar usuario/contraseña.

\n\n

Ejemplo de implementación de refresh:

\n\n
function refreshAccessToken(string $ref                    

Recommendations