@useoneauth/tokens
v1.0.0
Published
> Phase 4 — Token System. Stateless ES256 access-token JWTs + opaque rotated refresh tokens.
Readme
@useoneauth/tokens
Phase 4 — Token System. Stateless ES256 access-token JWTs + opaque rotated refresh tokens.
Pure TypeScript. Access tokens are short-lived ES256 JWTs (jose) verifiable
against a JWKS with no DB hit; refresh tokens are opaque, server-side, scrypt-
hashed secrets that rotate on every use with reuse-detection. Persistence (refresh
tokens) is behind an interface with an in-memory adapter; signing keys live in a
KeyStore.
Install
// package.json
{ "dependencies": { "@useoneauth/tokens": "workspace:*" } }Usage
import { TokenIssuer, TokenVerifier, InMemoryKeyStore, InMemoryRefreshTokenRepository } from "@useoneauth/tokens"
import { ScryptHasher } from "@useoneauth/crypto-core"
import { InMemoryEventBus } from "@useoneauth/events-core"
const keyStore = await InMemoryKeyStore.create()
const config = { issuer: "https://oneauth.example", audience: "https://api.example" }
const issuer = new TokenIssuer(keyStore, new InMemoryRefreshTokenRepository(), new ScryptHasher(), new InMemoryEventBus(), config)
const verifier = new TokenVerifier(keyStore, config)
// Issue an access JWT (5-min default) + an opaque refresh token, bound to a session.
const { accessToken, refreshToken } = await issuer.issueTokenPair({ identityId: "u1", sessionId: "s1", scope: ["read"] })
// Verify statelessly.
const claims = await verifier.verifyAccessToken(accessToken.token) // { sub, sid, scope, ... }
// Rotate: consumes the old refresh token, returns a fresh pair.
const rotated = await issuer.refresh({ refreshToken })
// Publish the JWKS (serve at /.well-known/jwks.json in a later server phase).
const jwks = await keyStore.getJWKS()Model
- Access token — stateless ES256 JWT; claims
sub(identity),sid(session),jti,iss,aud,iat,exp,scope. Not persisted. Default TTL 5 min. - Refresh token — raw value is
"<id>.<secret>": theidselects the stored record, thesecretis verified against its scrypt hash (salted hashes can't be looked up by value). Rotated on use; default TTL 30 days. - Reuse-detection — presenting a consumed refresh token revokes every refresh token for that session.
- KeyStore — generates an ES256 key pair, exposes a public JWKS, supports
rotate()(old keys retained for verification of in-flight tokens).
Events
TOKEN_ISSUED, TOKEN_REFRESHED, TOKEN_REVOKED.
Scope
Signing only (JWS, no JWE); no HTTP endpoints (the JWKS/token routes are a later server phase); no OAuth2/OIDC grant flows (Phase 11). Access-token verification is stateless — checking whether the bound session is still active is orchestration above this package.
See ARCHITECTURE.md.
