Volver a Explorar
EstándarTécnicoCiberseguridadIntermedio

JWS y JWT — formato estándar de firmas

6 minVerificado · 2026-05-18

JWSJSON Web Signature— es el estándar IETF (RFC 7515) que define cómo se firma una payload JSON. JWTJSON Web Token— es una aplicación específica de JWS donde la payload es un conjunto de claims sobre una entidad (típicamente un usuario).

Son las primitivas más usadas en internet moderno: OAuth 2.0, OpenID Connect, casi cualquier sistema de auth web, y la base de SD-JWT VC para credenciales verificables.

La estructura de un JWS / JWT

Un JWT es una cadena de tres partes separadas por puntos:

<base64url(header)>.<base64url(payload)>.<base64url(signature)>

Ejemplo concreto:

eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDp3ZWI6c2FsdGEuZ29iLmFyI2tleS0xIn0
.
eyJpc3MiOiJkaWQ6d2ViOnNhbHRhLmdvYi5hciIsInN1YiI6ImRpZDprZXk6ejZN
ay4uLiIsImlhdCI6MTcxNDUyMTYwMCwiZXhwIjoxNzQ2MDU3NjAwfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Cada parte es base64url-encoded para que el JWT sea seguro de transmitir en URLs y headers HTTP.

El header

El header contiene metadata sobre el JWT mismo:

{
  "alg": "EdDSA",
  "typ": "JWT",
  "kid": "did:web:salta.gob.ar#key-1"
}
  • alg indica el algoritmo de firma usado (EdDSA, ES256, RS256, etc.).
  • typ indica el tipo (JWT, o variantes como vc+sd-jwt para SD-JWT VC).
  • kid identifica qué clave del firmante se usó.

El payload

El payload contiene los claims (datos) del JWT:

{
  "iss": "did:web:salta.gob.ar",
  "sub": "did:key:z6Mk...",
  "iat": 1714521600,
  "exp": 1746057600,
  "nombre": "Juan Pérez",
  "domicilio": "Av. Belgrano 1234"
}

Hay claims estándar (registrados en IANA) y claims custom. Los estándar incluyen:

ClaimSignificado
issIssuer (quien firma)
subSubject (sobre quién es)
audAudience (a quién está dirigido)
iatIssued At (timestamp emisión)
expExpiration time (timestamp vencimiento)
nbfNot Before (timestamp de inicio de validez)
jtiJWT ID (identificador único)

La firma

La firma se calcula firmando base64url(header) + "." + base64url(payload) con la clave privada del firmante usando el algoritmo del header.

Para verificar:

  1. Decodificar header para saber qué algoritmo se usó.
  2. Identificar la clave pública del firmante (vía kid o vía DID resolution).
  3. Verificar la firma con la clave pública.

Por qué JWT se volvió ubicuo

Cinco razones que explican la adopción masiva de JWT en internet:

Self-contained

Un JWT contiene todos los datos necesarios para validar. No requiere consultar al issuer.

Stateless

El servidor no necesita guardar sesiones. El JWT mismo es la sesión.

Multi-format friendly

Base64url + JSON es seguro en URLs, headers HTTP, deep links, QR codes.

Standardizado

RFC 7515 + RFC 7519 son estables desde 2015. Implementaciones en cada lenguaje.

Extensible

Claims custom se pueden agregar sin romper compatibilidad.

Los problemas conocidos

A pesar de su éxito, JWT tiene problemas conocidos:

JWT vs SD-JWT VC

JWT clásico no soporta selective disclosure. SD-JWT VC es la extensión que lo agrega:

JWT clásicoSD-JWT VC
Estructuraheader.payload.signatureheader.payload.signaturedisclosure1disclosure2~...
Selective disclosureNoSí, nativo
Compatibilidad OAuth
Compatible W3C VCLimitadaCompleta

Para credenciales verificables modernas, SD-JWT VC es el formato. Pero JWT clásico sigue siendo válido para tokens de acceso y otros casos sin necesidad de selective disclosure.

Implementación

En código TypeScript/Node:

import { SignJWT, jwtVerify } from "jose";

// Firmar
const jwt = await new SignJWT({ nombre: "Juan", domicilio: "..." })
  .setProtectedHeader({ alg: "EdDSA", kid: "did:web:salta.gob.ar#key-1" })
  .setIssuer("did:web:salta.gob.ar")
  .setIssuedAt()
  .setExpirationTime("1y")
  .sign(privateKey);

// Verificar
const { payload } = await jwtVerify(jwt, publicKey, {
  issuer: "did:web:salta.gob.ar",
});

Librerías equivalentes existen en Python (PyJWT), Java (jjwt), Go (golang-jwt), Rust (jsonwebtoken).

Referencias

Relacionados

Tagsjwsjwtjsonietffirma