npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hemia/jwt-manager

v0.0.6

Published

Gestor de JWT seguro y extensible para aplicaciones Node.js

Readme

@hemia/jwt-manager

Una clase completa y robusta para la generación, validación y decodificación de tokens JWT con soporte completo para estándares OIDC (OpenID Connect) y OAuth 2.0. Ideal para gestionar autenticación y autorización basada en tokens dentro de aplicaciones Node.js modernas.


✨ Características principales

  • Estándares OIDC/OAuth 2.0: Claims estándar y tokens compatibles con especificaciones oficiales
  • 🔒 Seguridad mejorada: Algoritmos explícitos, validación de issuer/audience, clock skew tolerance
  • 🎯 Tres tipos de tokens: ID Token, Access Token y Refresh Token
  • 🔑 Gestión de permisos: Sistema de scopes para autorización granular
  • 📝 Claims estándar: Soporte completo para profile, email, phone, address claims
  • 🔄 Retrocompatible: Los métodos existentes siguen funcionando
  • 🛡️ Manejo de errores detallado: Identificación específica de tipos de error
  • 🚀 TypeScript nativo: Tipado completo y autocomplete

📦 Instalación

npm install @hemia/jwt-manager

🚀 Inicio rápido

import { JwtManager } from '@hemia/jwt-manager';

const jwtManager = new JwtManager();

// Crear un ID Token (OIDC)
const idToken = jwtManager.createIdToken({
    sub: 'user_12345',
    name: 'Cristian Mendez',
    email: '[email protected]',
    email_verified: true
}, '1h');

// Crear un Access Token con permisos
const accessToken = jwtManager.createAccessToken(
    'user_12345',
    ['read:products', 'write:orders'],
    '15m'
);

// Validar token
const payload = jwtManager.verify(accessToken);
if (payload) {
    console.log('✅ Token válido:', payload);
}

// Verificar permisos
const hasPermission = jwtManager.hasScope(accessToken, 'read:products');
console.log('Tiene permiso:', hasPermission);

📖 API Reference

🎫 Métodos de Creación de Tokens

createIdToken(claims, expiresIn?)

Crea un ID Token según estándar OIDC con información de identidad del usuario.

const idToken = jwtManager.createIdToken({
    sub: 'user_12345',              // Requerido
    name: 'Cristian Mendez',
    email: '[email protected]',
    email_verified: true,
    picture: 'https://example.com/avatar.jpg',
    preferred_username: 'cristianm',
    locale: 'es-MX'
}, '1h');

// Token contiene:
// {
//   sub, name, email, email_verified, picture, preferred_username, locale,
//   iss: 'hemia-app',
//   aud: 'hemia-api',
//   iat: 1703779200,
//   exp: 1703782800
// }

createAccessToken(sub, scopes, expiresIn?)

Crea un Access Token OAuth 2.0 con scopes para autorización.

const accessToken = jwtManager.createAccessToken(
    'user_12345',
    ['read:products', 'write:orders', 'admin:users'],
    '15m'  // Access tokens suelen ser de corta duración
);

// Token contiene:
// {
//   sub: 'user_12345',
//   scope: 'read:products write:orders admin:users',
//   iss: 'hemia-app',
//   aud: 'hemia-api',
//   iat: 1703779200,
//   exp: 1703780100
// }

createRefreshToken(sub, expiresIn?)

Crea un Refresh Token para renovar access tokens expirados.

const refreshToken = jwtManager.createRefreshToken('user_12345', '30d');

// Token contiene:
// {
//   sub: 'user_12345',
//   type: 'refresh',
//   jti: '1703779200-xyz123abc',  // JWT ID único para revocación
//   iss: 'hemia-app',
//   aud: 'hemia-api',
//   iat: 1703779200,
//   exp: 1706371200
// }

createToken(payload, expiresIn?, options?)

Crea un JWT genérico con payload personalizado (usa clave por defecto).

const token = jwtManager.createToken(
    { userId: 'abc123', role: 'admin' },
    '2h',
    { issuer: 'my-app' }  // Opcional
);

createTokenWithSecret(payload, secretKey, expiresIn?, options?)

Crea un JWT genérico con una clave secreta específica.

const token = jwtManager.createTokenWithSecret(
    { data: 'sensitive' },
    'custom-secret-key',
    '1h'
);

createCleanCredentialsToken(operative?, expiresIn?)

Crea un token especial para operaciones sin credenciales completas.

const token = jwtManager.createCleanCredentialsToken(Operatives.CATALOG, '2h');

✅ Métodos de Validación

verify(token, secretKey?, options?)

Valida un JWT y retorna el payload si es válido.

const payload = jwtManager.verify(token);

if (payload) {
    console.log('✅ Token válido');
    console.log('Usuario:', payload.sub);
    console.log('Email:', payload.email);
} else {
    console.log('❌ Token inválido o expirado');
}

// Con secret key personalizada
const payload2 = jwtManager.verify(token, 'custom-secret');

verifyDetailed(token, secretKey?, options?)

Valida un JWT y retorna resultado detallado con información de error.

const result = jwtManager.verifyDetailed(token);

console.log('Válido:', result.valid);

if (result.valid) {
    console.log('Payload:', result.payload);
} else {
    console.log('Error:', result.error);
    console.log('Tipo de error:', result.errorType);
    // errorType: 'expired' | 'invalid' | 'not_before' | 'malformed' | 'signature_invalid'
}

🔍 Métodos de Decodificación y Consulta

decode(token, complete?)

Decodifica un JWT sin validarlo (no verifica firma ni expiración).

// Solo payload
const payload = jwtManager.decode(token);

// Con header incluido
const full = jwtManager.decode(token, true);
console.log('Header:', full.header);    // { alg: 'HS256', typ: 'JWT' }
console.log('Payload:', full.payload);

getClaims(token)

Extrae solo los claims estándar OIDC de un token.

const claims = jwtManager.getClaims(token);
// Retorna solo: sub, name, email, email_verified, picture, etc.
// NO incluye: iss, aud, iat, exp (que son JWT claims)

hasScope(token, requiredScope)

Verifica si un token tiene un scope/permiso específico.

const canRead = jwtManager.hasScope(token, 'read:products');
const canDelete = jwtManager.hasScope(token, 'delete:products');

if (canRead) {
    console.log('✅ Usuario puede leer productos');
}

getJwtKey()

Obtiene la clave secreta configurada.

const secretKey = jwtManager.getJwtKey();

🔄 Métodos Legacy (Deprecated)

Estos métodos siguen funcionando para mantener compatibilidad hacia atrás:

// ⚠️ Deprecated - Usa createToken() en su lugar
jwtManager.getTokenWithoutKey(payload, expiresIn, options);

// ⚠️ Deprecated - Usa createTokenWithSecret() en su lugar
jwtManager.getTokenWithKey(payload, secretKey, expiresIn, options);

// ⚠️ Deprecated - Usa createCleanCredentialsToken() en su lugar
jwtManager.getTokenCleanCredentials(operative, expiresIn);

// ⚠️ Deprecated - Usa verify() en su lugar
jwtManager.validateToken(token, secretKey, options);

// ⚠️ Deprecated - Usa verifyDetailed() en su lugar
jwtManager.validateTokenDetailed(token, secretKey, options);

// ⚠️ Deprecated - Usa getClaims() en su lugar
jwtManager.getStandardClaims(token);

🔧 Configuración

Variables de entorno

# Clave secreta para firmar tokens (REQUERIDO en producción)
JWT_SECRET=tu_clave_super_secreta_aqui

# Emisor de los tokens (quien genera el token)
JWT_ISSUER=hemia-app

# Audiencia de los tokens (para quién es el token)
JWT_AUDIENCE=hemia-api

⚠️ Importante: Nunca uses una clave por defecto en producción. Define JWT_SECRET siempre en entornos seguros.


💡 Ejemplos de Uso

Ejemplo 1: Autenticación completa

import { JwtManager } from '@hemia/jwt-manager';

const jwtManager = new JwtManager();

// 1. Usuario inicia sesión
const idToken = jwtManager.createIdToken({
    sub: 'user_12345',
    name: 'Cristian Mendez',
    email: '[email protected]',
    email_verified: true
}, '1h');

const accessToken = jwtManager.createAccessToken(
    'user_12345',
    ['read:profile', 'read:products', 'write:orders'],
    '15m'
);

const refreshToken = jwtManager.createRefreshToken('user_12345', '30d');

// 2. Enviar tokens al cliente
res.json({ idToken, accessToken, refreshToken });

// 3. Cliente usa accessToken en requests
// Authorization: Bearer <accessToken>

// 4. Validar token en cada request
const payload = jwtManager.verify(accessToken);
if (!payload) {
    return res.status(401).json({ error: 'Token inválido' });
}

// 5. Verificar permisos específicos
if (!jwtManager.hasScope(accessToken, 'write:orders')) {
    return res.status(403).json({ error: 'Sin permisos' });
}

Ejemplo 2: Middleware de autenticación (Express)

import { Request, Response, NextFunction } from 'express';
import { JwtManager } from '@hemia/jwt-manager';

const jwtManager = new JwtManager();

// Middleware de autenticación
export const authenticateToken = (req: Request, res: Response, next: NextFunction) => {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

    if (!token) {
        return res.status(401).json({ error: 'Token no proporcionado' });
    }

    const payload = jwtManager.verify(token);

    if (!payload) {
        return res.status(403).json({ error: 'Token inválido o expirado' });
    }

    req.user = payload;
    next();
};

// Middleware de autorización por scope
export const requireScope = (requiredScope: string) => {
    return (req: Request, res: Response, next: NextFunction) => {
        const authHeader = req.headers['authorization'];
        const token = authHeader && authHeader.split(' ')[1];

        if (!token || !jwtManager.hasScope(token, requiredScope)) {
            return res.status(403).json({ 
                error: `Permiso denegado. Se requiere: ${requiredScope}` 
            });
        }

        next();
    };
};

// Uso en rutas
app.get('/profile', authenticateToken, (req, res) => {
    res.json({ user: req.user });
});

app.get('/products', authenticateToken, requireScope('read:products'), (req, res) => {
    res.json({ products: [...] });
});

app.post('/orders', authenticateToken, requireScope('write:orders'), (req, res) => {
    res.json({ success: true });
});

Ejemplo 3: Manejo de errores detallado

const result = jwtManager.verifyDetailed(token);

if (!result.valid) {
    switch (result.errorType) {
        case 'expired':
            // Token expirado - solicitar refresh
            return res.status(401).json({ 
                error: 'Token expirado',
                code: 'TOKEN_EXPIRED',
                message: 'Por favor renueva tu sesión'
            });
        
        case 'signature_invalid':
            // Firma inválida - posible manipulación
            console.error('⚠️ Token con firma inválida detectado');
            return res.status(403).json({ 
                error: 'Token inválido',
                code: 'INVALID_SIGNATURE' 
            });
        
        case 'not_before':
            // Token aún no válido
            return res.status(403).json({ 
                error: 'Token no válido aún',
                code: 'TOKEN_NOT_YET_VALID' 
            });
        
        default:
            return res.status(403).json({ 
                error: 'Token inválido',
                code: 'INVALID_TOKEN' 
            });
    }
}

// Token válido
console.log('Usuario autenticado:', result.payload.sub);

Ejemplo 4: Renovar tokens con Refresh Token

app.post('/auth/refresh', async (req, res) => {
    const { refreshToken } = req.body;

    // Validar refresh token
    const payload = jwtManager.verify(refreshToken);

    if (!payload || payload.type !== 'refresh') {
        return res.status(401).json({ error: 'Refresh token inválido' });
    }

    // Opcional: Verificar que el jti no esté en lista negra
    // const isRevoked = await checkIfRevoked(payload.jti);
    // if (isRevoked) return res.status(401).json({ error: 'Token revocado' });

    // Generar nuevos tokens
    const newAccessToken = jwtManager.createAccessToken(
        payload.sub,
        ['read:profile', 'read:products'],
        '15m'
    );

    const newRefreshToken = jwtManager.createRefreshToken(payload.sub, '30d');

    res.json({ 
        accessToken: newAccessToken, 
        refreshToken: newRefreshToken 
    });
});

📚 TypeScript Types

import { 
    JwtManager, 
    StandardClaims, 
    TokenPayload, 
    TokenValidationResult,
    TokenType 
} from '@hemia/jwt-manager';

// StandardClaims (OIDC)
interface StandardClaims {
    sub: string;                    // Subject (required)
    name?: string;
    given_name?: string;
    family_name?: string;
    email?: string;
    email_verified?: boolean;
    picture?: string;
    // ... más claims
}

// TokenValidationResult
interface TokenValidationResult {
    valid: boolean;
    payload?: any;
    error?: string;
    errorType?: 'expired' | 'invalid' | 'not_before' | 'malformed' | 'signature_invalid';
}

// TokenType
enum TokenType {
    ID_TOKEN = 'id_token',
    ACCESS_TOKEN = 'access_token',
    REFRESH_TOKEN = 'refresh_token'
}

🔒 Mejoras de Seguridad Implementadas

✅ Algoritmo Explícito

Previene ataques de confusión de algoritmo especificando siempre HS256 o RS256.

✅ Validación de Issuer y Audience

Verifica que el token fue emitido por quien dice serlo y para la audiencia correcta.

✅ Clock Skew Tolerance

30 segundos de tolerancia para diferencias de reloj entre servidores.

✅ JWT ID (jti) para Refresh Tokens

Permite implementar revocación de tokens mediante lista negra.

✅ Lista Blanca de Algoritmos

Solo acepta HS256 y RS256, rechazando algoritmos inseguros como none.


📖 Documentación Adicional

Para más ejemplos y documentación detallada, consulta USAGE_EXAMPLES.md.


🌐 Recursos


📄 Licencia

MIT — Desarrollado por Hemia Technologies