hwtr-js
JavaScript-Referenzimplementierung des HWT-Protokolls github. Demos dazu unter hwt-demo github.
Offizielle Dokumentation Issues
Token-Format: hwt.signature.key-id.expires-unix-seconds.format.payload
Installation
// Deno / JSR
import Hwtr from 'jsr:@hwt/hwtr-js'
// Node / Bun via JSR
// npx jsr add @hwt/hwtr-js
// Lokal
import Hwtr from './hwtr.js'
Schnellstart
// Schlüssel einmalig generieren – Ergebnis sicher speichern
const keyConfig = await Hwtr.generateKeys({ type: 'Ed25519' })
// Instanz erstellen
const hwtr = await Hwtr.factory({}, keyConfig)
// Signieren
const token = await hwtr.create({ sub: 'user:123', role: 'editor' })
// Verifizieren
const result = await hwtr.verify(token)
if (result.ok) {
console.log(result.data) // { sub: 'user:123', role: 'editor' }
}
API
Hwtr.factory(options, keyConfig) → Promise<Hwtr>
Bevorzugter Konstruktor. Äquivalent zu new Hwtr(options).importKeys(keyConfig).
const hwtr = await Hwtr.factory({ expiresInSeconds: 3600 }, keyConfig)
Konstruktoroptionen – alle optional:
| Option | Standard | Beschreibung |
|---|---|---|
expiresInSeconds |
60 |
Standard-Token-Lebensdauer |
maxTokenLifetimeSeconds |
86400 |
Harte Obergrenze; 0 = unbegrenzt |
leewaySeconds |
1 |
Toleranz für Uhrzeitabweichung. Die Spec empfiehlt nicht mehr als 5 Minuten (300 s); kein Maximum wird erzwungen. |
maxTokenSizeBytes |
4096 |
Bereich: 512–16384 |
format |
'j' |
payload-Codec |
signatureSize |
0 |
HMAC-Signatur auf N Zeichen kürzen; 0 = vollständig; für asymmetrische Schlüssel ignoriert |
throwOnInvalid |
false |
Ausnahme werfen statt ok: false zurückzugeben |
throwOnExpired |
false |
Ausnahme werfen statt ok: false zurückzugeben |
throwOnGenerate |
true |
Ausnahme bei Signierfehler werfen |
throwOnEncoding |
true |
Ausnahme bei Codec-Fehler werfen |
Schlüsselgenerierung
// Vollständiges Schlüssel-Set – direkt an factory oder importKeys übergeben
const keyConfig = await Hwtr.generateKeys({
count: 2, // Anzahl der Schlüssel (Standard: 1)
current: 'primary', // Id des Signing-Schlüssels
type: 'Ed25519', // Algorithmus (Standard: 'HMAC')
})
// → { current, type, keys: [{ id, created, privateKey, publicKey }] }
// Einzelner HMAC-Schlüssel
const key = Hwtr.generateKey({ id: 'main' })
// → { id, secret, created }
// Einzelnes asymmetrisches Schlüsselpaar
const pair = await Hwtr.generateKeyPair({ id: 'k1', type: 'ECDSA-P256' })
// → { id, created, publicKey, privateKey } (base64url SPKI/PKCS8)
Unterstützte Algorithmen: 'HMAC', 'Ed25519', 'ECDSA-P256', 'ECDSA-P384', 'ECDSA-P521'
HMAC ist symmetrisch – nur für Single-Service geeignet. Verwenden Sie asymmetrische Typen für serviceübergreifende Verifizierung. P-521-Unterstützung variiert je nach Umgebung; vor dem Einsatz testen.
hwtr.importKeys(keyConfig) → Promise<Hwtr>
Importiert Signing- und/oder Verifizierungsschlüssel. factory() ruft dies für Sie auf.
// keyConfig-Struktur
{
current: 'primary', // Id des Schlüssels zum Signieren neuer Tokens
type: 'Ed25519',
keys: [
{ id: 'primary', created: '...', privateKey: 'BASE64URL', publicKey: 'BASE64URL' }
// HMAC: { id, created, secret }
],
publicKeys: { // optional: reine Verifizierungsschlüssel von anderen Services
'partner-key': 'BASE64URL'
}
}
Mehrere Schlüssel werden für die Rotation unterstützt. Jeder Schlüssel, dessen id mit dem kid eines Tokens übereinstimmt, kann diesen verifizieren. Nur der Schlüssel mit id === current signiert neue Tokens.
hwtr.create(payload, hiddenData?) → Promise<string>
Erstellt einen Token mit der Standard-Ablaufzeit.
const token = await hwtr.create({ sub: 'user:123' })
// hiddenData wird signiert, aber nicht eingebettet – Verifier (Prüfer) muss denselben Wert angeben
const token = await hwtr.create({ sub: 'user:123' }, { ip: '203.0.113.1' })
Gibt '' zurück (oder wirft eine Ausnahme, wenn throwOnInvalid), wenn der Token maxTokenSizeBytes überschreiten würde.
hwtr.createWith(expiresInSeconds, payload, hiddenData?) → Promise<string>
Erstellt einen Token mit einer bestimmten Lebensdauer. Wirft eine Ausnahme, wenn diese maxTokenLifetimeSeconds überschreitet.
const token = await hwtr.createWith(300, { sub: 'user:123', oneTime: true })
hwtr.verify(token, hiddenData?) → Promise<VerifyResult>
Verifiziert Signatur und Ablaufzeit. Wirft standardmäßig keine Ausnahme.
const result = await hwtr.verify(token)
// result.ok — true if valid
// result.data — decoded payload
// result.expired — true if past expiry
// result.expires — unix seconds
// result.error — present on any failure
result.error-Werte: 'hwt invalid', 'hwt invalid format', 'hwt expired', 'hwt unknown encoding "x"', 'hwt unknown key', 'hwt invalid signature', 'hwt data decoding failed'
hwtr.decode(token) → Promise<{ data, expires, error? }>
Dekodiert den payload, ohne Signatur oder Ablaufzeit zu prüfen. Nur zur Inspektion.
Serviceübergreifende Verifizierung
Ein Service, der nur verifiziert (kein Signing), übergibt publicKeys ohne private keys:
const verifyOnly = await Hwtr.factory({}, {
type: 'Ed25519',
keys: [],
publicKeys: { 'auth-key': 'BASE64URL' }
})
Hilfsmethoden für die Schlüsselverteilung:
const pub = await hwtr.exportPublicKey('primary') // base64url SPKI string
const all = await hwtr.getPublicKeys() // { id: base64url, ... }
await hwtr.addPublicKey({ id, publicKeyBase64, type }) // externen Schlüssel zur Laufzeit hinzufügen
Codecs
'j' (JSON) ist der einzige eingebaute Codec. Registrieren Sie eigene Codecs einmalig pro Prozess:
Hwtr.registerFormat('name', {
encode(data) { /* → Uint8Array */ },
decode(buffer) { /* → value */ }
})
Hwtr.formats // → ['j', 'name', ...]
Format-Namen: /^[a-zA-Z][a-zA-Z0-9]{1,19}$/. Bereits registrierte Namen werfen eine Ausnahme.
Ein erweiterter JSON-Codec (jx) mit Unterstützung für Date, BigInt, Map, Set und typisierte Arrays ist im Quellrepository unter hwtr.formats.js verfügbar – er ist nicht im veröffentlichten Paket enthalten.
Hilfsfunktionen
Hwtr.timingSafeEqual(a, b) // Vergleich in konstanter Zeit; Strings oder Uint8Array
Hwtr.bufferToBase64Url(buffer) // ArrayBuffer | Uint8Array → base64url string
Hwtr.base64urlToUint8Array(str) // base64url → Uint8Array; empty array on bad input
Hwtr.textToBase64Url(text) // UTF-8 string → base64url
Hwtr.base64urlToText(str) // base64url → UTF-8 string
Hwtr.isHwt(str) // true, wenn str ein plausibles HWT-Signatur-Segment enthält
Hwtr.ALGORITHMS // unterstützte Algorithmen-Map
Hwtr.version // Version
Alle auch als Named Exports aus hwtr.js verfügbar.
Verwandte Ressourcen
Lizenz
Copyright 2026 Jim Montgomery
SPDX-License-Identifier: Apache-2.0
Apache License 2.0. Siehe LICENSE.