@purecore-br/jwt
v0.1.0
Published
One JWT FTW is a library for validating and verifying JSON Web Tokens (JWT) using always the newest and more secure native cryptographic algorithm.
Readme
Uma biblioteca moderna e opinativa para criação e validação de JSON Web Tokens (JWT) usando exclusivamente algoritmos state-of-the-art. API compatível com jose, mas com uma filosofia radicalmente diferente: Opinião Forte.
🎯 Filosofia "One JWT 4 ALL"
Enquanto outras bibliotecas suportam centenas de combinações de algoritmos (muitos deles inseguros ou obsoletos), nós suportamos apenas uma combinação para cada caso de uso. Essa combinação é escolhida com base no que há de mais seguro e performático na versão LTS mais recente do Node.js.
Por que EdDSA (Ed25519)?
- ⚡ Mais rápido que ECDSA e RSA
- 🔑 Chaves menores que RSA (256 bits vs 2048+ bits)
- 🛡️ Imune a ataques de timing e side-channels comuns
- 📦 Suporte nativo no Node.js 18+ (sem dependências externas)
- ✅ Padrão moderno recomendado por criptógrafos
"A complexidade é a inimiga da segurança."
📊 Comparativo: jose vs Purecore JWTfy
| Funcionalidade | Biblioteca jose (Genérica) | Purecore JWTfy (Opinativa) | | --------------------- | ---------------------------------------- | ------------------------------------------- | | Filosofia | Suportar tudo (Legado & Novo) | Suportar apenas o Melhor (State-of-the-Art) | | JWS Signing Algs | HS256, RS256, ES256, PS256, EdDSA... | EdDSA (Ed25519) Apenas | | JWE Encryption | RSA-OAEP, A128CBC-HS256, A256GCM... | X25519 + A256GCM (Roadmap) | | JWS Serialization | Compact, Flattened, General | Compact (Core) | | Key Management | JWK, JWKS (Local/Remote), PEM, X.509 | PEM & JWK (Simples) | | Runtime | Universal (Browser, Node, Deno, Workers) | Node.js Nativo (Foco em Performance) | | Dependências | Múltiplas | Zero (0) |
🚀 Instalação
# Com npm
npm install @purecore/one-jwt-4-all
# Com bun
bun add @purecore/one-jwt-4-all
# Com yarn
yarn add @purecore/one-jwt-4-all📖 Uso Básico
1. Gerar Par de Chaves
import { generateKeyPair } from "@purecore/one-jwt-4-all";
const { publicKey, privateKey } = generateKeyPair();
// Salve as chaves de forma segura
console.log("Chave Privada:", privateKey);
console.log("Chave Pública:", publicKey);2. Criar um Token JWT
import { SignJWT } from "@purecore/one-jwt-4-all";
// Criar token com builder pattern (estilo jose)
const jwt = await new SignJWT({
userId: 123,
email: "[email protected]",
role: "admin",
})
.setProtectedHeader({ alg: "EdDSA", typ: "JWT" })
.setIssuedAt()
.setIssuer("urn:meu-sistema:issuer")
.setAudience("urn:meu-sistema:audience")
.setExpirationTime("2h") // Expira em 2 horas
.setSubject("usuario-123")
.setJti("token-unique-id")
.sign(privateKey);
console.log("Token gerado:", jwt);3. Verificar um Token JWT
import { jwtVerify } from "@purecore/one-jwt-4-all";
try {
const { payload, protectedHeader } = await jwtVerify(jwt, publicKey, {
issuer: "urn:meu-sistema:issuer",
audience: "urn:meu-sistema:audience",
maxTokenAge: "2h", // Opcional: idade máxima do token
});
console.log("Token válido!");
console.log("Payload:", payload);
console.log("Header:", protectedHeader);
} catch (error) {
console.error("Token inválido:", error.message);
}🔧 API Completa
SignJWT (Builder Pattern)
Métodos Disponíveis
new SignJWT(payload: JWTPayload)
.setProtectedHeader(header: JWTHeaderParameters) // Define o header protegido
.setIssuer(issuer: string) // Define o emissor (iss)
.setSubject(subject: string) // Define o assunto (sub)
.setAudience(audience: string | string[]) // Define a audiência (aud)
.setJti(jwtId: string) // Define o ID único do token (jti)
.setIssuedAt(timestamp?: number) // Define quando foi emitido (iat)
.setExpirationTime(time: number | string) // Define expiração (exp)
.setNotBefore(time: number | string) // Define quando fica válido (nbf)
.sign(privateKey: KeyObject | string) // Assina e retorna o tokenFormatos de Tempo Suportados
// Strings de duração relativa
.setExpirationTime('30s') // 30 segundos
.setExpirationTime('5m') // 5 minutos
.setExpirationTime('2h') // 2 horas
.setExpirationTime('1d') // 1 dia
.setExpirationTime('1w') // 1 semana
.setExpirationTime('1y') // 1 ano
// Timestamp absoluto (Unix timestamp em segundos)
.setExpirationTime(1735689600)jwtVerify (Função)
jwtVerify(
jwt: string,
publicKey: KeyObject | string,
options?: JWTVerifyOptions
): Promise<JWTVerifyResult>Opções de Verificação
interface JWTVerifyOptions {
issuer?: string | string[]; // Valida o emissor (iss)
audience?: string | string[]; // Valida a audiência (aud)
algorithms?: string[]; // Lista de algoritmos permitidos (ignorado, sempre EdDSA)
currentDate?: Date; // Data atual para testes (mock)
maxTokenAge?: string | number; // Idade máxima do token ('2h' ou segundos)
}📝 Exemplos Práticos
Exemplo 1: Autenticação de Usuário
import { SignJWT, jwtVerify, generateKeyPair } from "@purecore/one-jwt-4-all";
// Gere as chaves uma vez e guarde em variáveis de ambiente
const { publicKey, privateKey } = generateKeyPair();
// Login: Criar token após autenticação bem-sucedida
async function login(userId: string, email: string) {
const token = await new SignJWT({
userId,
email,
loginTime: Date.now(),
})
.setIssuedAt()
.setIssuer("https://meuapp.com")
.setAudience("https://meuapp.com/api")
.setSubject(userId)
.setExpirationTime("24h")
.sign(privateKey);
return token;
}
// Middleware: Verificar token em requisições
async function verifyToken(token: string) {
try {
const { payload } = await jwtVerify(token, publicKey, {
issuer: "https://meuapp.com",
audience: "https://meuapp.com/api",
maxTokenAge: "24h",
});
return payload;
} catch (error) {
throw new Error(`Token inválido: ${error.message}`);
}
}Exemplo 2: Refresh Tokens
// Access Token (curta duração)
const accessToken = await new SignJWT({ userId: 123 })
.setIssuedAt()
.setExpirationTime("15m") // 15 minutos
.setIssuer("https://meuapp.com")
.setAudience("https://meuapp.com/api")
.sign(privateKey);
// Refresh Token (longa duração)
const refreshToken = await new SignJWT({ userId: 123 })
.setIssuedAt()
.setExpirationTime("7d") // 7 dias
.setIssuer("https://meuapp.com")
.setAudience("https://meuapp.com/auth/refresh")
.sign(privateKey);Exemplo 3: Tokens com Not Before
// Token que só fica válido após 5 minutos
const token = await new SignJWT({ userId: 123 })
.setIssuedAt()
.setNotBefore("5m") // Válido apenas após 5 minutos
.setExpirationTime("1h")
.sign(privateKey);Exemplo 4: Integração com Express.js
import express from "express";
import { jwtVerify } from "@purecore/one-jwt-4-all";
import { readFileSync } from "fs";
const app = express();
const publicKey = readFileSync("./public-key.pem", "utf-8");
// Middleware de autenticação
async function authenticate(
req: express.Request,
res: express.Response,
next: express.NextFunction
) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
return res.status(401).json({ error: "Token não fornecido" });
}
const token = authHeader.substring(7);
try {
const { payload } = await jwtVerify(token, publicKey, {
issuer: "https://meuapp.com",
audience: "https://meuapp.com/api",
});
req.user = payload;
next();
} catch (error) {
return res.status(401).json({ error: `Token inválido: ${error.message}` });
}
}
// Rota protegida
app.get("/api/protected", authenticate, (req, res) => {
res.json({
message: "Acesso autorizado",
user: req.user,
});
});🔒 Segurança
Boas Práticas
Nunca exponha a chave privada
- Guarde em variáveis de ambiente
- Use serviços de gerenciamento de segredos em produção
Use expiração curta para access tokens
- Recomendado: 15 minutos a 1 hora
- Use refresh tokens para renovação
Valide sempre issuer e audience
- Previne uso de tokens em contextos errados
- Protege contra token reuse attacks
Use HTTPS em produção
- Tokens não devem trafegar em conexões não criptografadas
Rotacione chaves periodicamente
- Gere novos pares de chaves regularmente
- Mantenha versões antigas para validação durante transição
Gerenciamento de Chaves
// Gerar par de chaves
const { publicKey, privateKey } = generateKeyPair();
// Salvar em arquivos (nunca commite no git!)
import { writeFileSync } from "fs";
writeFileSync("./private-key.pem", privateKey, { mode: 0o600 }); // Permissões restritas
writeFileSync("./public-key.pem", publicKey);
// Carregar de arquivos
import { readFileSync } from "fs";
const privateKey = readFileSync("./private-key.pem", "utf-8");
const publicKey = readFileSync("./public-key.pem", "utf-8");🧪 Testes
import { SignJWT, jwtVerify, generateKeyPair } from "@purecore/one-jwt-4-all";
describe("JWT", () => {
const { publicKey, privateKey } = generateKeyPair();
it("deve criar e verificar token válido", async () => {
const jwt = await new SignJWT({ userId: 123 })
.setIssuedAt()
.setExpirationTime("1h")
.sign(privateKey);
const { payload } = await jwtVerify(jwt, publicKey);
expect(payload.userId).toBe(123);
});
it("deve rejeitar token expirado", async () => {
const jwt = await new SignJWT({ userId: 123 })
.setIssuedAt()
.setExpirationTime("-1h") // Expirado
.sign(privateKey);
await expect(jwtVerify(jwt, publicKey)).rejects.toThrow("expirado");
});
});📚 Tipos TypeScript
A biblioteca exporta todos os tipos necessários:
import type {
JWTPayload,
JWTHeaderParameters,
JWTVerifyResult,
JWTVerifyOptions,
} from "@purecore/one-jwt-4-all";🔄 Exemplos Avançados
1. Self-Healing Agentic Conversational System
Sistema onde dois agentes se identificam usando JWTs do mesmo servidor e regeneram automaticamente seus tokens quando expiram, mantendo a conversa contínua sem interrupção.
Características:
- ✅ Auto-Renovação: Tokens renovados automaticamente antes de expirar
- ✅ Contexto Preservado: Conversa continua mesmo após renovação
- ✅ Verificação Mútua: Agentes verificam identidade uns dos outros
- ✅ Self-Healing: Sistema se recupera automaticamente de falhas
Exemplo Rápido:
import {
TokenAuthority,
SelfHealingAgent,
} from "./examples/self-healing-agents";
const authority = new TokenAuthority();
const agentA = new SelfHealingAgent("agent-alpha", "primary", authority);
const agentB = new SelfHealingAgent("agent-beta", "secondary", authority);
await agentA.initialize();
await agentB.initialize();
agentA.startAutoRenewal(30000);
agentB.startAutoRenewal(30000);
await agentA.sendMessage(agentB, "Olá! Vamos trabalhar juntos?");
await agentB.sendMessage(agentA, "Perfeito! Estou pronto.");📖 Documentação: examples/SELF_HEALING_AGENTS.md
2. Self-Healing Agents com mTLS (Mutual TLS)
Extensão do sistema anterior que adiciona mTLS para segurança em duas camadas: transporte (certificados) + aplicação (JWT).
Características:
- 🔒 mTLS: Autenticação mútua via certificados X.509
- 🔐 JWT: Autenticação de identidade e contexto
- 🛡️ Prevenção MITM: Certificados validam identidade do transporte
- 🔄 Self-Healing: Auto-renovação de tokens mantendo conexão mTLS
Exemplo Rápido:
import {
mTLSAgent,
CertificateAuthority,
TokenAuthority,
} from "./examples/mtls-agents";
const ca = new CertificateAuthority();
const tokenAuthority = new TokenAuthority();
const certA = ca.generateAgentCertificate("agent-alpha");
const certB = ca.generateAgentCertificate("agent-beta");
const caCert = ca.getCACertificate();
const agentA = new mTLSAgent(
"agent-alpha",
"primary",
tokenAuthority,
certA,
caCert
);
const agentB = new mTLSAgent(
"agent-beta",
"secondary",
tokenAuthority,
certB,
caCert
);
await agentA.initialize();
await agentB.initialize();
await agentA.startTLSServer(8443);
await agentB.startTLSServer(8444);
await agentA.connectToPeer("localhost", 8444, "agent-beta");
await agentB.connectToPeer("localhost", 8443, "agent-alpha");
// Comunicação segura via mTLS + JWT
await agentA.sendMessage("agent-beta", "Mensagem segura!");📖 Documentação: examples/MTLS_AGENTS.md
3. Signal Protocol E2EE (End-to-End Encryption)
Implementação do Double Ratchet Algorithm do Signal Protocol para criptografia end-to-end entre agentes com Perfect Forward Secrecy.
Características:
- 🔐 X3DH: Extended Triple Diffie-Hellman para key agreement
- 🔄 Double Ratchet: Rotação contínua de chaves por mensagem
- 🛡️ Perfect Forward Secrecy (PFS): Comprometimento não afeta passado
- 🔓 Post-Compromise Security (PCS): Recuperação após comprometimento
- 🤫 Deniability: Negabilidade criptográfica
Exemplo Rápido:
import { SignalE2EEAgent, TokenAuthority } from "./examples/signal-e2ee-agents";
const tokenAuthority = new TokenAuthority();
const alice = new SignalE2EEAgent("alice", tokenAuthority);
const bob = new SignalE2EEAgent("bob", tokenAuthority);
await alice.initialize();
await bob.initialize();
// Trocar bundles públicos
alice.registerPeerBundle("bob", bob.getPublicKeyBundle());
bob.registerPeerBundle("alice", alice.getPublicKeyBundle());
// Estabelecer sessão E2EE
await alice.establishSession("bob");
await bob.acceptSession(
"alice",
alice.getIdentityPublicKey(),
alice.getPublicKeyBundle().signedPreKey
);
// Enviar mensagem encriptada
const msg = await alice.sendMessage("bob", "Hello, secure world!");
const plaintext = await bob.receiveMessage(msg);
// plaintext = "Hello, secure world!"📖 Documentação: examples/SIGNAL_E2EE.md
4. Combinando Signal E2EE + mTLS (Defesa em Profundidade)
Para máxima segurança, combine ambos os protocolos:
| Camada | Protocolo | Proteção | | -------------- | ----------- | ------------------------------------ | | Transporte | mTLS | Anti-MITM, autenticação mútua | | Aplicação | Signal E2EE | Forward secrecy, conteúdo encriptado | | Contexto | JWT | Claims, autorização, expiração |
📖 Documentação Completa: examples/SIGNAL_E2EE.md#usando-ambos-em-conjunto
🛠️ Requisitos
- Node.js: >= 18.0.0 (suporte nativo a Ed25519)
- TypeScript: >= 4.0.0 (recomendado)
📄 Licença
Este projeto é licenciado sob a Cogfulness Ethical License (CEL) - uma licença open source focada em uso ético e responsável de tecnologia cognitiva.
🤝 Contribuindo
Contribuições são bem-vindas! Este projeto segue uma filosofia de zero dependencies e simplicidade arquitetural.
🔗 Links Úteis
- RFC 7519 - JSON Web Token (JWT)
- RFC 8037 - Edwards-Curve Digital Signature Algorithm (EdDSA)
- Node.js Crypto Documentation
- JWT.io - Debugger de Tokens
📝 Changelog
Veja todas as mudanças em CHANGELOG.md
Desenvolvido com ❤️ para promover segurança através de simplicidade e opiniões fortes.
