hwtr-js

HWTプロトコル githubのJavaScriptリファレンス実装。 このライブラリを使ったデモはhwt-demo githubを参照。

正規ドキュメント issues

Token format: hwt.signature.key-id.expires-unix-seconds.format.payload


インストール

// Deno / JSR
import Hwtr from 'jsr:@hwt/hwtr-js'

// Node / Bun via JSR
// npx jsr add @hwt/hwtr-js

// ローカル
import Hwtr from './hwtr.js'

クイックスタート

// 鍵を一度生成し、結果を安全に保管する
const keyConfig = await Hwtr.generateKeys({ type: 'Ed25519' })

// インスタンスを生成
const hwtr = await Hwtr.factory({}, keyConfig)

// 署名
const token = await hwtr.create({ sub: 'user:123', role: 'editor' })

// 検証
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>

推奨コンストラクター。new Hwtr(options).importKeys(keyConfig)と等価。

const hwtr = await Hwtr.factory({ expiresInSeconds: 3600 }, keyConfig)

コンストラクターオプション — すべてオプション:

オプション デフォルト 説明
expiresInSeconds 60 デフォルトトークンライフタイム
maxTokenLifetimeSeconds 86400 ハード上限;0 = 無制限
leewaySeconds 1 クロックスキュー許容値。specは5分(300秒)を超えないことを推奨;最大値の強制はない。
maxTokenSizeBytes 4096 範囲:512〜16384
format 'j' payloadのcodec
signatureSize 0 HMAC署名をN文字に切り詰める;0 = フル長;非対称鍵では無視される
throwOnInvalid false ok: falseを返す代わりにthrowする
throwOnExpired false ok: falseを返す代わりにthrowする
throwOnGenerate true 署名失敗時にthrowする
throwOnEncoding true codec失敗時にthrowする

鍵の生成

// 完全な鍵セット — factoryまたはimportKeysに直接渡す
const keyConfig = await Hwtr.generateKeys({
  count: 2,           // 鍵の数(デフォルト:1)
  current: 'primary', // 署名鍵のid
  type: 'Ed25519',    // アルゴリズム(デフォルト:'HMAC')
})
// → { current, type, keys: [{ id, created, privateKey, publicKey }] }

// 単一のHMAC鍵
const key = Hwtr.generateKey({ id: 'main' })
// → { id, secret, created }

// 単一の非対称鍵ペア
const pair = await Hwtr.generateKeyPair({ id: 'k1', type: 'ECDSA-P256' })
// → { id, created, publicKey, privateKey }  (base64url SPKI/PKCS8)

サポートされているアルゴリズム:'HMAC''Ed25519''ECDSA-P256''ECDSA-P384''ECDSA-P521'

HMACは対称鍵 — 単一サービス専用。クロスサービス検証には非対称鍵タイプを使用すること。P-521のサポートは環境によって異なる;使用前にテストすること。


hwtr.importKeys(keyConfig)Promise<Hwtr>

署名鍵および/または検証鍵をインポートする。factory()が自動的に呼び出す。

// keyConfigの構造
{
  current: 'primary',    // 新しいトークンの署名に使用する鍵のid
  type: 'Ed25519',
  keys: [
    { id: 'primary', created: '...', privateKey: 'BASE64URL', publicKey: 'BASE64URL' }
    // HMAC: { id, created, secret }
  ],
  publicKeys: {          // オプション:他サービスからの検証専用鍵
    'partner-key': 'BASE64URL'
  }
}

ローテーションのために複数の鍵をサポートする。idがトークンのkidと一致する任意の鍵で検証できる。id === currentの鍵のみが新しいトークンに署名する。


hwtr.create(payload, hiddenData?)Promise<string>

デフォルトの有効期限でトークンを生成する。

const token = await hwtr.create({ sub: 'user:123' })

// hiddenDataは署名されるが埋め込まれない — verifierは同一の値を提供する必要がある
const token = await hwtr.create({ sub: 'user:123' }, { ip: '203.0.113.1' })

トークンがmaxTokenSizeBytesを超える場合、''を返す(throwOnInvalidの場合はthrow)。


hwtr.createWith(expiresInSeconds, payload, hiddenData?)Promise<string>

指定したライフタイムでトークンを生成する。maxTokenLifetimeSecondsを超える場合はthrowする。

const token = await hwtr.createWith(300, { sub: 'user:123', oneTime: true })

hwtr.verify(token, hiddenData?)Promise<VerifyResult>

署名と有効期限を検証する。デフォルトではthrowしない。

const result = await hwtr.verify(token)
// result.ok      — 有効な場合はtrue
// result.data    — デコードされたpayload
// result.expired — 有効期限切れの場合はtrue
// result.expires — unix秒
// result.error   — 失敗時に存在

result.errorの値:'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? }>

署名や有効期限を検証せずにpayloadをデコードする。検査専用。


クロスサービス検証

検証のみ(署名なし)のサービスは、秘密keysなしでpublicKeysを渡す:

const verifyOnly = await Hwtr.factory({}, {
  type: 'Ed25519',
  keys: [],
  publicKeys: { 'auth-key': 'BASE64URL' }
})

鍵配布のための便利メソッド:

const pub = await hwtr.exportPublicKey('primary')       // base64url SPKI文字列
const all = await hwtr.getPublicKeys()                  // { id: base64url, ... }
await hwtr.addPublicKey({ id, publicKeyBase64, type })  // ランタイムに外部鍵を追加

Codec

'j'(JSON)が唯一の組み込みcodecである。カスタムcodecをプロセスごとに一度登録する:

Hwtr.registerFormat('name', {
  encode(data) { /* → Uint8Array */ },
  decode(buffer) { /* → value */ }
})
Hwtr.formats // → ['j', 'name', ...]

フォーマット名:/^[a-zA-Z][a-zA-Z0-9]{1,19}$/。登録済みの名前はthrowする。

拡張JSONcodec(jx)はDateBigIntMapSet、typed arrayをサポートし、ソースリポジトリのhwtr.formats.jsで利用可能 — 公開パッケージには含まれていない。


ユーティリティ

Hwtr.timingSafeEqual(a, b)      // 定数時間比較;文字列またはUint8Array
Hwtr.bufferToBase64Url(buffer)  // ArrayBuffer | Uint8Array → base64url文字列
Hwtr.base64urlToUint8Array(str) // base64url → Uint8Array;不正な入力の場合は空配列
Hwtr.textToBase64Url(text)      // UTF-8文字列 → base64url
Hwtr.base64urlToText(str)       // base64url → UTF-8文字列
Hwtr.isHwt(str)                 // strが有効なHWT署名セグメントを含む場合にtrue
Hwtr.ALGORITHMS                 // サポートされているアルゴリズムマップ
Hwtr.version                    // バージョン

すべてhwtr.jsからnamed exportとしてもエクスポートされる。


関連


ライセンス

Copyright 2026 Jim Montgomery
SPDX-License-Identifier: Apache-2.0

Apache License 2.0。LICENSEを参照。