20-El token

  Los datos van en el body de la petición y el token va en el header por separado.

✅ CORRECTO: El token solo contiene información de autenticación (quién eres), no los datos de tu petición.

✅ INCORRECTO: Los registros NO van dentro del token.

Flujo detallado:

1. Login (obtener token)

text
POST /login
Body: { "email": "usuario@ejemplo.com", "password": "123456" }

2. Servidor responde con token

json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0IiwiaWF0IjoxNj...",
  "user": { "id": 1234, "name": "Juan" }
}

3. Peticiones posteriores (con token)

text
POST /guardar-registro
Headers: {
  "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "Content-Type": "application/json"
}
Body: {
  "producto": "Laptop",
  "precio": 999.99,
  "cantidad": 5
}

¿Qué contiene el token?

Típicamente información de identificación:

json
{
  "userId": "1234",
  "username": "juan123",
  "iat": 1627837283,      // Fecha de emisión
  "exp": 1627840883       // Fecha de expiración
}

Ventajas de este enfoque:

  • Stateless: El servidor no guarda sesiones

  • Escalable: Fácil de manejar en múltiples servidores

  • Seguro: El token puede tener expiración y firma digital

¿Te queda claro cómo separamos la autenticación (header) de los datos (body)?


¡Exacto! 🎯 Has entendido perfectamente. Así es exactamente como funciona:


Flujo correcto:

1. Registro/Login (Cliente → Servidor)

text
POST /auth/login
Body: {
  "email": "usuario@ejemplo.com",
  "password": "mi_password"
}

2. Respuesta del Servidor (Servidor → Cliente)

json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 123,
    "name": "Juan Pérez",
    "email": "usuario@ejemplo.com"
  }
}

3. Peticiones posteriores (Cliente → Servidor)

text
POST /api/guardar-producto
Headers: {
  "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "Content-Type": "application/json"
}
Body: {
  "nombre": "Laptop Gamer",
  "precio": 1500,
  "categoria": "Tecnología"
}

¿Qué hace el servidor con el token?

  1. Recibe la petición con el token en el header Authorization

  2. Verifica que el token sea válido y esté firmado por él mismo

  3. Extrae la información del usuario (ej: userId: 123)

  4. Procesa los datos del body usando la identidad del usuario

  5. Responde al cliente


Ejemplo en código (Node.js/Express):

javascript
// Middleware para verificar token
const verifyToken = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'Token requerido' });
  }

  try {
    // Verificar y decodificar token
    const decoded = jwt.verify(token, 'clave_secreta');
    req.user = decoded; // Agregar info del usuario a la request
    next(); // Continuar con la ruta
  } catch (error) {
    return res.status(403).json({ error: 'Token inválido' });
  }
};

// Ruta protegida
app.post('/api/guardar-producto', verifyToken, (req, res) => {
  // req.user contiene la info del token (ej: { userId: 123 })
  // req.body contiene los datos del producto
  
  const nuevoProducto = {
    ...req.body,
    usuarioId: req.user.userId, // Relacionar con el usuario
    fechaCreacion: new Date()
  };

  // Guardar en base de datos...
  console.log('Producto guardado:', nuevoProducto);
  
  res.json({ success: true, producto: nuevoProducto });
});

Resumen final:

  • ✅ Token en headers: Autenticación (¿quién eres?)

  • ✅ Datos en body: Información de la petición (¿qué quieres hacer?)

  • ✅ Separación clara: Seguridad y organización

¡Perfecto! Ahora tienes claro el concepto. ¿Te gustaría ver algún ejemplo específico o tienes otra duda? 😊

Exactamente! 🎯 Lo has entendido perfectamente. Así es como funciona paso a paso:


Flujo completo y correcto:

1. Registro inicial (Crear cuenta)

text
POST /auth/register
Body: {
  "email": "usuario@ejemplo.com",
  "password": "mi_password_123",
  "name": "Juan Pérez"
}
  • El servidor guarda tu usuario y contraseña (encriptada) en la base de datos

  • Todavía no hay token

2. Login (Obtener token)

text
POST /auth/login  
Body: {
  "email": "usuario@ejemplo.com",
  "password": "mi_password_123"
}
  • ✅ Servidor verifica que las credenciales sean correctas

  • ✅ Genera el token con información como:

json
{
  "userId": "123",
  "email": "usuario@ejemplo.com",
  "iat": 1627837283,       // Fecha de creación
  "exp": 1627840883        // Fecha de expiración (ej: 1 hora)
}
  • ✅ Firma el token con una clave secreta que solo el servidor conoce

  • ✅ Envía el token al cliente

3. Peticiones con token

text
GET /api/mis-datos
Headers: {
  "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
  • 🔍 Servidor verifica:

    • ¿El token está bien formado?

    • ¿La firma es válida? (¿lo firmé yo?)

    • ¿No ha expirado?

    • ¿El usuario todavía existe?

4. Procesamiento

  • Si TODO ES VÁLIDO: Procesa tu petición y te responde

  • Si ALGO FALLA: Retorna error 401 Unauthorized o 403 Forbidden


Ejemplo de verificación en el servidor:

javascript
const jwt = require('jsonwebtoken');
const CLAVE_SECRETA = 'mi_clave_super_secreta';

// Middleware de verificación
function verificarToken(req, res, next) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(401).json({ error: 'Token requerido' });
  }

  try {
    // Verificar y decodificar el token
    const decoded = jwt.verify(token, CLAVE_SECRETA);
    
    // decoded = { userId: "123", email: "usuario@ejemplo.com", iat: 1627837283, exp: 1627840883 }
    
    req.usuario = decoded; // Agregar info del usuario a la request
    next(); // Continuar con la petición
    
  } catch (error) {
    return res.status(403).json({ error: 'Token inválido o expirado' });
  }
}

// Uso en una ruta protegida
app.get('/api/mis-datos', verificarToken, (req, res) => {
  // Solo llega aquí si el token es válido
  console.log('Usuario autenticado:', req.usuario.userId);
  // Procesar la petición...
});

¿Qué pasa si alguien modifica el token?

Si un cliente intenta modificar el token (ej: cambiar userId: 123 por userId: 456):

  1. La firma digital dejará de coincidir

  2. jwt.verify() fallará inmediatamente

  3. El servidor rechazará la petición


Resumen:

✅ Credenciales correctas → Servidor genera y firma token
✅ Cliente envía token en headers + datos en body
✅ Servidor verifica firma y validez
✅ Si todo ok → Procesa la petición
❌ Si algo falla → Rechaza la petición

¡Perfecto! Ahora sí tienes el concepto 100% claro. ¿Te queda alguna duda? 


Te muestro un ejemplo completo en PHP:

1. Instalación necesaria

bash
composer require firebase/php-jwt

2. Login - Generar Token

php
<?php
require 'vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class AuthController {
    // ¡ESTA CLAVE DEBE SER SECRETA Y SEGURA!
    private $clave_secreta = "mi_clave_super_secreta_2024";
    
    public function login($email, $password) {
        // 1. Verificar credenciales en la base de datos
        $usuario = $this->verificarCredenciales($email, $password);
        
        if (!$usuario) {
            return ["error" => "Credenciales inválidas"];
        }
        
        // 2. Datos para incluir en el token
        $payload = [
            "iss" => "mi-servidor.com",    // Emisor
            "aud" => "mi-aplicacion",      // Audiencia
            "iat" => time(),               // Fecha de emisión
            "exp" => time() + (60*60),     // Expira en 1 hora
            "data" => [                    // Datos del usuario
                "userId" => $usuario['id'],
                "email" => $usuario['email'],
                "name" => $usuario['name']
            ]
        ];
        
        // 3. Generar token firmado
        $jwt = JWT::encode($payload, $this->clave_secreta, 'HS256');
        
        return [
            "token" => $jwt,
            "user" => [
                "id" => $usuario['id'],
                "name" => $usuario['name'],
                "email" => $usuario['email']
            ]
        ];
    }
    
    private function verificarCredenciales($email, $password) {
        // Simulación de verificación en BD
        $usuarios = [
            [
                'id' => 1,
                'email' => 'usuario@ejemplo.com',
                'password' => password_hash('password123', PASSWORD_DEFAULT),
                'name' => 'Juan Pérez'
            ]
        ];
        
        foreach ($usuarios as $usuario) {
            if ($usuario['email'] === $email && 
                password_verify($password, $usuario['password'])) {
                return $usuario;
            }
        }
        return false;
    }
}
?>

3. Middleware para verificar token

php
<?php
function verificarToken() {
    $clave_secreta = "mi_clave_super_secreta_2024";
    
    // Obtener token del header
    $headers = apache_request_headers();
    if (!isset($headers['Authorization'])) {
        http_response_code(401);
        echo json_encode(["error" => "Token no proporcionado"]);
        exit;
    }
    
    $authHeader = $headers['Authorization'];
    $token = str_replace('Bearer ', '', $authHeader);
    
    try {
        // Verificar y decodificar el token
        $decoded = JWT::decode($token, new Key($clave_secreta, 'HS256'));
        return $decoded;
        
    } catch (Exception $e) {
        http_response_code(403);
        echo json_encode(["error" => "Token inválido: " . $e->getMessage()]);
        exit;
    }
}
?>

4. Ruta protegida

php
<?php
// Ejemplo de endpoint protegido
header('Content-Type: application/json');

// Verificar token
$usuarioAutenticado = verificarToken();

// Si llegó aquí, el token es válido
$datosPeticion = json_decode(file_get_contents('php://input'), true);

// Procesar la petición
$response = [
    "success" => true,
    "message" => "Petición procesada correctamente",
    "usuario" => $usuarioAutenticado->data,
    "datosRecibidos" => $datosPeticion
];

echo json_encode($response);
?>

5. Ejemplo de uso desde cliente

php
<?php
// Cliente haciendo petición con token
$token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."; // Token recibido en login

$data = [
    "producto" => "Laptop Gamer",
    "precio" => 1500,
    "cantidad" => 2
];

$options = [
    'http' => [
        'header'  => [
            "Authorization: Bearer " . $token,
            "Content-Type: application/json"
        ],
        'method'  => 'POST',
        'content' => json_encode($data)
    ]
];

$context  = stream_context_create($options);
$result = file_get_contents('http://tuservidor.com/api/guardar-producto', false, $context);
echo $result;
?>

¡IMPORTANTE! Sobre la clave secreta:

✅ Sí, tú proporcionas la clave secreta
✅ Debe ser una cadena larga y compleja (mínimo 32 caracteres)
✅ Nunca la expongas en código público
✅ Guárdala en variables de entorno
✅ Usa diferentes claves para entornos de desarrollo y producción

Recomendación para clave segura:

php
// En producción, usa variables de entorno
$clave_secreta = getenv('JWT_SECRET_KEY');

// O genera una clave segura:
$clave_secreta = bin2hex(random_bytes(32)); // 64 caracteres hexadecimales

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