@holeauth/core 0.0.1-alpha.0 → 0.0.2-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- export { d as definePlugin } from '../index-CotvcK_b.js';
2
- export { H as HookRunner, P as PluginRegistry, b as buildRegistry, e as emptyRegistry, r as runOnInit } from '../registry-CZhM1tEB.js';
3
- export { C as ChallengeResult, g as HoleauthHooks, H as HoleauthPlugin, w as PasswordChangeHookInput, x as PasswordResetHookInput, m as PluginContext, n as PluginCoreSurface, o as PluginEvents, p as PluginLogger, q as PluginRoute, r as PluginRouteContext, P as PluginsApi, y as RegisterHookInput, z as SessionIssueHookData, A as SessionRevokeHookData, D as SessionRotateHookData } from '../index-BmYQquGs.js';
1
+ export { d as definePlugin } from '../index-BydOBZfs.js';
2
+ export { H as HookRunner, P as PluginRegistry, b as buildRegistry, e as emptyRegistry, r as runOnInit } from '../registry-B-I45f0J.js';
3
+ export { C as ChallengeResult, g as HoleauthHooks, H as HoleauthPlugin, x as PasswordChangeHookInput, y as PasswordResetHookInput, m as PluginContext, n as PluginCoreSurface, o as PluginEvents, p as PluginLogger, q as PluginRoute, r as PluginRouteContext, P as PluginsApi, z as RegisterHookInput, A as SessionIssueHookData, D as SessionRevokeHookData, E as SessionRotateHookData } from '../index-Bt3CyLaq.js';
4
4
  import '../index-CNtnPdzk.js';
@@ -1,4 +1,4 @@
1
- import { C as ChallengeResult, k as IssuedTokens, H as HoleauthPlugin, q as PluginRoute, m as PluginContext, a as HoleauthConfig } from './index-BmYQquGs.js';
1
+ import { C as ChallengeResult, k as IssuedTokens, H as HoleauthPlugin, q as PluginRoute, m as PluginContext, a as HoleauthConfig } from './index-Bt3CyLaq.js';
2
2
  import { A as AdapterUser } from './index-CNtnPdzk.js';
3
3
 
4
4
  interface PluginRegistry {
@@ -1,3 +1,3 @@
1
- export { G as GetSessionOrRefreshInput, a as GetSessionOrRefreshResult, I as IssueInput, g as getSessionOrRefresh, b as issueSession, r as revokeAllForUser, c as revokeByRefresh, d as revokeSession, e as rotateRefresh, s as sha256b64url, v as validateSession } from '../index-D57PvFMN.js';
2
- import '../index-BmYQquGs.js';
1
+ export { G as GetSessionOrRefreshInput, a as GetSessionOrRefreshResult, I as IssueInput, R as RequestRefreshResult, g as getSessionOrRefresh, b as getSessionOrRefreshFromRequest, c as issueSession, r as revokeAllForUser, d as revokeByRefresh, e as revokeSession, f as rotateRefresh, s as sha256b64url, v as validateSession } from '../index-D0r6eY4L.js';
2
+ import '../index-Bt3CyLaq.js';
3
3
  import '../index-CNtnPdzk.js';
@@ -341,6 +341,94 @@ async function getSessionOrRefresh(instance, input) {
341
341
  return { session, tokens, refreshed: true };
342
342
  }
343
343
 
344
- export { getSessionOrRefresh, issueSession, revokeAllForUser, revokeByRefresh, revokeSession, rotateRefresh, sha256b64url, validateSession };
344
+ // src/cookies/spec.ts
345
+ function cookieName(cfg, kind) {
346
+ const prefix = cfg.tokens?.cookiePrefix ?? "holeauth";
347
+ switch (kind) {
348
+ case "access":
349
+ return `${prefix}.at`;
350
+ case "refresh":
351
+ return `${prefix}.rt`;
352
+ case "csrf":
353
+ return `${prefix}.csrf`;
354
+ case "pending":
355
+ return `${prefix}.pending`;
356
+ case "oauthState":
357
+ return `${prefix}.oauth.state`;
358
+ case "oauthPkce":
359
+ return `${prefix}.oauth.pkce`;
360
+ }
361
+ }
362
+ function isProduction() {
363
+ return globalThis.process?.env?.NODE_ENV === "production";
364
+ }
365
+ function buildCookie(cfg, input) {
366
+ const httpOnly = input.httpOnly ?? input.kind !== "csrf";
367
+ const secure = cfg.tokens?.cookieSecure ?? isProduction();
368
+ return {
369
+ name: cookieName(cfg, input.kind),
370
+ value: input.value,
371
+ maxAge: input.maxAge,
372
+ httpOnly,
373
+ secure,
374
+ sameSite: input.sameSite ?? cfg.tokens?.sameSite ?? "lax",
375
+ path: input.path ?? "/",
376
+ domain: cfg.tokens?.cookieDomain
377
+ };
378
+ }
379
+ function serializeCookie(c) {
380
+ const parts = [`${c.name}=${encodeURIComponent(c.value)}`];
381
+ parts.push(`Path=${c.path}`);
382
+ if (c.domain) parts.push(`Domain=${c.domain}`);
383
+ if (c.maxAge !== void 0) {
384
+ parts.push(`Max-Age=${c.maxAge}`);
385
+ if (c.maxAge === 0) parts.push("Expires=Thu, 01 Jan 1970 00:00:00 GMT");
386
+ }
387
+ if (c.httpOnly) parts.push("HttpOnly");
388
+ if (c.secure) parts.push("Secure");
389
+ parts.push(`SameSite=${c.sameSite.charAt(0).toUpperCase()}${c.sameSite.slice(1)}`);
390
+ return parts.join("; ");
391
+ }
392
+
393
+ // src/session/request.ts
394
+ function parseCookies(header) {
395
+ const out = {};
396
+ if (!header) return out;
397
+ for (const part of header.split(";")) {
398
+ const i = part.indexOf("=");
399
+ if (i < 0) continue;
400
+ const k = part.slice(0, i).trim();
401
+ const v = decodeURIComponent(part.slice(i + 1).trim());
402
+ if (k) out[k] = v;
403
+ }
404
+ return out;
405
+ }
406
+ function buildSetCookieHeaders(cfg, tokens) {
407
+ const accessTtl = cfg.tokens?.accessTtl ?? 900;
408
+ const refreshTtl = cfg.tokens?.refreshTtl ?? 2592e3;
409
+ return [
410
+ serializeCookie(buildCookie(cfg, { kind: "access", value: tokens.accessToken, maxAge: accessTtl })),
411
+ serializeCookie(buildCookie(cfg, { kind: "refresh", value: tokens.refreshToken, maxAge: refreshTtl })),
412
+ serializeCookie(buildCookie(cfg, { kind: "csrf", value: tokens.csrfToken, maxAge: refreshTtl, httpOnly: false }))
413
+ ];
414
+ }
415
+ async function getSessionOrRefreshFromRequest(req, instance) {
416
+ const cfg = instance.config;
417
+ const jar = parseCookies(req.headers.get("cookie"));
418
+ const accessToken = jar[cookieName(cfg, "access")];
419
+ const refreshToken = jar[cookieName(cfg, "refresh")];
420
+ const ip = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0;
421
+ const userAgent = req.headers.get("user-agent") ?? void 0;
422
+ const result = await getSessionOrRefresh(instance, {
423
+ accessToken,
424
+ refreshToken,
425
+ ip,
426
+ userAgent
427
+ });
428
+ const setCookieHeaders = result.tokens ? buildSetCookieHeaders(cfg, result.tokens) : [];
429
+ return { ...result, setCookieHeaders };
430
+ }
431
+
432
+ export { getSessionOrRefresh, getSessionOrRefreshFromRequest, issueSession, revokeAllForUser, revokeByRefresh, revokeSession, rotateRefresh, sha256b64url, validateSession };
345
433
  //# sourceMappingURL=index.js.map
346
434
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors/index.ts","../../src/jwt/index.ts","../../src/cookies/csrf.ts","../../src/events/emitter.ts","../../src/plugins/runner-ref.ts","../../src/session/hash.ts","../../src/session/issue.ts","../../src/session/rotate.ts","../../src/session/validate.ts","../../src/session/revoke.ts","../../src/session/get-or-refresh.ts"],"names":["ACCESS_DEFAULT","REFRESH_DEFAULT","session"],"mappings":"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","file":"index.js","sourcesContent":["export class HoleauthError extends Error {\n readonly code: string;\n readonly status: number;\n constructor(code: string, message: string, status = 400) {\n super(message);\n this.name = 'HoleauthError';\n this.code = code;\n this.status = status;\n }\n}\nexport class InvalidTokenError extends HoleauthError {\n constructor(message = 'Invalid token') { super('INVALID_TOKEN', message, 401); }\n}\nexport class SessionExpiredError extends HoleauthError {\n constructor(message = 'Session expired') { super('SESSION_EXPIRED', message, 401); }\n}\nexport class AdapterError extends HoleauthError {\n constructor(message = 'Adapter error') { super('ADAPTER_ERROR', message, 500); }\n}\nexport class ProviderError extends HoleauthError {\n constructor(message = 'Provider error') { super('PROVIDER_ERROR', message, 502); }\n}\nexport class CsrfError extends HoleauthError {\n constructor(message = 'CSRF validation failed') { super('CSRF_FAILED', message, 403); }\n}\nexport class CredentialsError extends HoleauthError {\n constructor(message = 'Invalid credentials') { super('INVALID_CREDENTIALS', message, 401); }\n}\nexport class AccountConflictError extends HoleauthError {\n constructor(message = 'Account conflict') { super('ACCOUNT_CONFLICT', message, 409); }\n}\nexport class RefreshReuseError extends HoleauthError {\n constructor(message = 'Refresh token reuse detected') { super('REFRESH_REUSE', message, 401); }\n}\nexport class PendingChallengeError extends HoleauthError {\n constructor(message = 'Pending challenge required') { super('PENDING_CHALLENGE', message, 401); }\n}\nexport class RegistrationDisabledError extends HoleauthError {\n constructor(message = 'Self-registration is disabled') { super('REGISTRATION_DISABLED', message, 403); }\n}\nexport class NotSupportedError extends HoleauthError {\n constructor(message = 'Operation not supported by adapter') { super('NOT_SUPPORTED', message, 501); }\n}\n","import { SignJWT, jwtVerify, decodeJwt, type JWTPayload } from 'jose';\nimport { InvalidTokenError } from '../errors/index.js';\n\nfunction toKey(secret: string | Uint8Array): Uint8Array {\n return typeof secret === 'string' ? new TextEncoder().encode(secret) : secret;\n}\n\nexport interface SignOptions {\n issuer?: string;\n audience?: string;\n subject?: string;\n expiresIn?: string | number; // e.g. '15m' or seconds\n jti?: string;\n}\n\nexport async function sign(\n payload: JWTPayload,\n secret: string | Uint8Array,\n opts: SignOptions = {},\n): Promise<string> {\n const jwt = new SignJWT(payload).setProtectedHeader({ alg: 'HS256' }).setIssuedAt();\n if (opts.issuer) jwt.setIssuer(opts.issuer);\n if (opts.audience) jwt.setAudience(opts.audience);\n if (opts.subject) jwt.setSubject(opts.subject);\n if (opts.jti) jwt.setJti(opts.jti);\n if (opts.expiresIn !== undefined) jwt.setExpirationTime(opts.expiresIn);\n return jwt.sign(toKey(secret));\n}\n\nexport async function verify<T extends JWTPayload = JWTPayload>(\n token: string,\n secret: string | Uint8Array,\n): Promise<T> {\n try {\n const { payload } = await jwtVerify(token, toKey(secret));\n return payload as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n\nexport function decode<T extends JWTPayload = JWTPayload>(token: string): T {\n try {\n return decodeJwt(token) as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n","/**\n * Double-submit CSRF protection.\n * The cookie holeauth.csrf is readable by JS (httpOnly:false). The client\n * echoes its value in header `x-csrf-token`; the server compares the two.\n * Because cross-origin JS cannot read the cookie, an attacker cannot mint\n * a matching header, defeating the cross-site POST scenario.\n */\n\nconst b64urlChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\nexport function generateCsrfToken(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n let out = '';\n for (const b of bytes) out += b64urlChars[b % 64];\n return out;\n}\n\n/** Constant-time compare. */\nexport function verifyCsrf(cookieValue: string | undefined, headerValue: string | undefined): boolean {\n if (!cookieValue || !headerValue) return false;\n if (cookieValue.length !== headerValue.length) return false;\n let diff = 0;\n for (let i = 0; i < cookieValue.length; i++) {\n diff |= cookieValue.charCodeAt(i) ^ headerValue.charCodeAt(i);\n }\n return diff === 0;\n}\n\nexport const CSRF_HEADER = 'x-csrf-token';\n","import type { HoleauthConfig } from '../types/index.js';\nimport type { HoleauthEvent } from './types.js';\n\ntype Handler = (e: HoleauthEvent) => void | Promise<void>;\n\ninterface EventBus {\n byType: Map<string, Set<Handler>>;\n wildcard: Set<Handler>;\n}\n\nconst busByConfig = new WeakMap<HoleauthConfig, EventBus>();\n\nfunction getBus(cfg: HoleauthConfig): EventBus {\n let bus = busByConfig.get(cfg);\n if (!bus) {\n bus = { byType: new Map(), wildcard: new Set() };\n busByConfig.set(cfg, bus);\n }\n return bus;\n}\n\n/** Subscribe to an event type. Use '*' to match all events. Returns an unsubscribe fn. */\nexport function subscribe(cfg: HoleauthConfig, type: string, handler: Handler): () => void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.add(handler);\n return () => bus.wildcard.delete(handler);\n }\n let set = bus.byType.get(type);\n if (!set) {\n set = new Set();\n bus.byType.set(type, set);\n }\n set.add(handler);\n return () => set!.delete(handler);\n}\n\nexport function unsubscribe(cfg: HoleauthConfig, type: string, handler: Handler): void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.delete(handler);\n return;\n }\n bus.byType.get(type)?.delete(handler);\n}\n\n/**\n * emit() persists the event via the mandatory AuditLogAdapter and\n * additionally fans out to all subscribers (typed + wildcard) plus the\n * legacy `cfg.onEvent` hook — all fire-and-forget so business flows are\n * never blocked by observer failures.\n *\n * Callers MUST await emit(): audit persistence is a hard requirement.\n */\nexport async function emit(cfg: HoleauthConfig, event: HoleauthEvent): Promise<void> {\n const withTimestamp: HoleauthEvent = { at: new Date(), ...event };\n await cfg.adapters.auditLog.record(withTimestamp);\n\n const bus = getBus(cfg);\n const typed = bus.byType.get(withTimestamp.type);\n const fire = (h: Handler) => {\n Promise.resolve()\n .then(() => h(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n };\n if (typed) for (const h of typed) fire(h);\n for (const h of bus.wildcard) fire(h);\n\n if (cfg.onEvent) {\n Promise.resolve()\n .then(() => cfg.onEvent?.(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n }\n}\n","/**\n * Per-config hook runner attachment. Stored via WeakMap so the runner is\n * reachable from low-level helpers (session/issue, session/rotate, …)\n * without threading it through every signature.\n *\n * `defineHoleauth()` attaches the runner once at instance creation.\n */\nimport type { HoleauthConfig } from '../types/index.js';\nimport type { HookRunner } from './registry.js';\n\nconst runners = new WeakMap<HoleauthConfig, HookRunner>();\n\nexport function attachHookRunner(cfg: HoleauthConfig, runner: HookRunner): void {\n runners.set(cfg, runner);\n}\n\nconst NOOP: HookRunner = {\n async runRegisterBefore() {},\n async runRegisterAfter() {},\n async runSignInBefore() {},\n async runSignInChallenge() { return null; },\n async runSignInAfter() {},\n async runSignOutAfter() {},\n async runRefreshBefore() {},\n async runRefreshAfter() {},\n async runPasswordChangeBefore() {},\n async runPasswordChangeAfter() {},\n async runPasswordResetBefore() {},\n async runPasswordResetAfter() {},\n async runUserUpdateAfter() {},\n async runUserDeleteAfter() {},\n async runSessionIssue() {},\n async runSessionRotate() {},\n async runSessionRevoke() {},\n};\n\nexport function getHookRunner(cfg: HoleauthConfig): HookRunner {\n return runners.get(cfg) ?? NOOP;\n}\n","/** SHA-256 → base64url. Works on Node 20+ and all Edge runtimes. */\nexport async function sha256b64url(input: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));\n const bytes = new Uint8Array(buf);\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","import type { HoleauthConfig, IssuedTokens } from '../types/index.js';\nimport { sign } from '../jwt/index.js';\nimport { generateCsrfToken } from '../cookies/csrf.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\nimport { sha256b64url } from './hash.js';\n\nconst ACCESS_DEFAULT = 900; // 15m\nconst REFRESH_DEFAULT = 2592000; // 30d\n\nexport interface IssueInput {\n userId: string;\n /** Omit to start a fresh family (e.g. on a real login). */\n familyId?: string;\n ip?: string | null;\n userAgent?: string | null;\n}\n\n/**\n * Mint a brand new session row + JWT pair + CSRF token.\n * Used by: fresh login, passkey login, SSO callback, 2FA verify.\n */\nexport async function issueSession(cfg: HoleauthConfig, input: IssueInput): Promise<IssuedTokens> {\n const accessTtl = cfg.tokens?.accessTtl ?? ACCESS_DEFAULT;\n const refreshTtl = cfg.tokens?.refreshTtl ?? REFRESH_DEFAULT;\n const now = Math.floor(Date.now() / 1000);\n\n const familyId = input.familyId ?? crypto.randomUUID();\n const sessionId = crypto.randomUUID();\n const nonce = crypto.randomUUID();\n\n const [accessToken, refreshToken] = await Promise.all([\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${accessTtl}s` },\n ),\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, typ: 'refresh', nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${refreshTtl}s`, jti: nonce },\n ),\n ]);\n const refreshTokenHash = await sha256b64url(refreshToken);\n\n await cfg.adapters.session.createSession({\n id: sessionId,\n userId: input.userId,\n familyId,\n refreshTokenHash,\n expiresAt: new Date((now + refreshTtl) * 1000),\n createdAt: new Date(),\n revokedAt: null,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n });\n\n const csrfToken = generateCsrfToken();\n\n await emit(cfg, {\n type: 'session.created',\n userId: input.userId,\n sessionId,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n data: { familyId },\n });\n await getHookRunner(cfg).runSessionIssue({ userId: input.userId, sessionId, familyId });\n\n return {\n accessToken,\n refreshToken,\n csrfToken,\n sessionId,\n familyId,\n accessExpiresAt: (now + accessTtl) * 1000,\n refreshExpiresAt: (now + refreshTtl) * 1000,\n };\n}\n","import type { HoleauthConfig, IssuedTokens } from '../types/index.js';\nimport { sign, verify } from '../jwt/index.js';\nimport { generateCsrfToken } from '../cookies/csrf.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\nimport { sha256b64url } from './hash.js';\nimport { InvalidTokenError, RefreshReuseError, SessionExpiredError } from '../errors/index.js';\n\nconst ACCESS_DEFAULT = 900;\nconst REFRESH_DEFAULT = 2592000;\n\n/**\n * Rotate-on-use with reuse detection.\n *\n * 1. Decode refresh JWT → recover sid, fam, sub.\n * 2. Hash presented token; look it up.\n * - If not found, the token was already rotated away → reuse! Revoke family.\n * 3. Issue new access + refresh, rotate hash in storage atomically.\n *\n * Returns a fresh IssuedTokens tuple. Session id + family stay stable.\n */\nexport async function rotateRefresh(\n cfg: HoleauthConfig,\n presentedRefresh: string,\n meta: { ip?: string | null; userAgent?: string | null } = {},\n): Promise<IssuedTokens> {\n let claims: { sid?: string; sub?: string; fam?: string; typ?: string; exp?: number };\n try {\n claims = await verify(presentedRefresh, cfg.secrets.jwtSecret);\n } catch {\n throw new InvalidTokenError('refresh token invalid');\n }\n if (claims.typ !== 'refresh' || !claims.sid || !claims.sub || !claims.fam) {\n throw new InvalidTokenError('refresh claims malformed');\n }\n\n const presentedHash = await sha256b64url(presentedRefresh);\n const found = await cfg.adapters.session.getByRefreshHash(presentedHash);\n\n if (!found || found.revokedAt) {\n // Reuse detected — revoke whole family, record an event, throw.\n await cfg.adapters.session.revokeFamily(claims.fam);\n await emit(cfg, {\n type: 'session.reuse_detected',\n userId: claims.sub,\n sessionId: claims.sid,\n ip: meta.ip ?? null,\n userAgent: meta.userAgent ?? null,\n data: { familyId: claims.fam },\n });\n throw new RefreshReuseError();\n }\n\n if (found.expiresAt.getTime() < Date.now()) {\n await cfg.adapters.session.revokeFamily(claims.fam);\n throw new SessionExpiredError();\n }\n\n const accessTtl = cfg.tokens?.accessTtl ?? ACCESS_DEFAULT;\n const refreshTtl = cfg.tokens?.refreshTtl ?? REFRESH_DEFAULT;\n const now = Math.floor(Date.now() / 1000);\n const nonce = crypto.randomUUID();\n\n const [accessToken, refreshToken] = await Promise.all([\n sign(\n { sid: found.id, sub: found.userId, fam: found.familyId, nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${accessTtl}s` },\n ),\n sign(\n { sid: found.id, sub: found.userId, fam: found.familyId, typ: 'refresh', nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${refreshTtl}s`, jti: nonce },\n ),\n ]);\n const newHash = await sha256b64url(refreshToken);\n await cfg.adapters.session.rotateRefresh(\n found.id,\n newHash,\n new Date((now + refreshTtl) * 1000),\n );\n\n await emit(cfg, {\n type: 'session.rotated',\n userId: found.userId,\n sessionId: found.id,\n ip: meta.ip ?? null,\n userAgent: meta.userAgent ?? null,\n data: { familyId: found.familyId },\n });\n await getHookRunner(cfg).runSessionRotate({\n userId: found.userId,\n sessionId: found.id,\n familyId: found.familyId,\n });\n\n return {\n accessToken,\n refreshToken,\n csrfToken: generateCsrfToken(),\n sessionId: found.id,\n familyId: found.familyId,\n accessExpiresAt: (now + accessTtl) * 1000,\n refreshExpiresAt: (now + refreshTtl) * 1000,\n };\n}\n","import type { HoleauthConfig, SessionData } from '../types/index.js';\nimport { verify } from '../jwt/index.js';\n\n/**\n * Edge-compatible: verifies the access JWT only. Does not touch adapters.\n * Use this in middleware / hot paths.\n */\nexport async function validateSession(cfg: HoleauthConfig, token: string): Promise<SessionData | null> {\n try {\n const p = await verify<{ sid: string; sub: string; fam?: string; exp?: number }>(\n token,\n cfg.secrets.jwtSecret,\n );\n if (!p.sid || !p.sub) return null;\n return {\n sessionId: p.sid,\n userId: p.sub,\n expiresAt: (p.exp ?? 0) * 1000,\n familyId: p.fam,\n };\n } catch {\n return null;\n }\n}\n","import type { HoleauthConfig } from '../types/index.js';\nimport { verify } from '../jwt/index.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\n\n/** Revoke a single session by id (signout). */\nexport async function revokeSession(cfg: HoleauthConfig, sessionId: string, userId?: string): Promise<void> {\n await cfg.adapters.session.deleteSession(sessionId);\n await emit(cfg, {\n type: 'session.revoked',\n userId: userId ?? null,\n sessionId,\n });\n await getHookRunner(cfg).runSessionRevoke({ userId: userId ?? null, sessionId });\n}\n\n/** Revoke by presented refresh token (best-effort). */\nexport async function revokeByRefresh(cfg: HoleauthConfig, refreshToken: string): Promise<void> {\n try {\n const p = await verify<{ sid?: string; sub?: string }>(refreshToken, cfg.secrets.jwtSecret);\n if (p.sid) {\n await cfg.adapters.session.deleteSession(p.sid);\n await emit(cfg, { type: 'session.revoked', userId: p.sub ?? null, sessionId: p.sid });\n await getHookRunner(cfg).runSessionRevoke({ userId: p.sub ?? null, sessionId: p.sid });\n }\n } catch { /* ignore */ }\n}\n\n/** Global signout — all sessions for a user. */\nexport async function revokeAllForUser(cfg: HoleauthConfig, userId: string): Promise<void> {\n if (cfg.adapters.session.revokeUser) {\n await cfg.adapters.session.revokeUser(userId);\n await emit(cfg, { type: 'session.revoked', userId, data: { scope: 'all' } });\n await getHookRunner(cfg).runSessionRevoke({ userId, sessionId: null, scope: 'all' });\n }\n}\n","import type {\n HoleauthInstance,\n IssuedTokens,\n SessionData,\n} from '../types/index.js';\nimport { validateSession } from './validate.js';\n\nexport interface GetSessionOrRefreshInput {\n /** Current access token (if any). */\n accessToken?: string | null;\n /** Current refresh token (if any). When present, used to rotate on access miss. */\n refreshToken?: string | null;\n /** Request metadata, forwarded to refresh hooks/audit log. */\n ip?: string;\n userAgent?: string;\n}\n\nexport interface GetSessionOrRefreshResult {\n /** Resolved session, or null if both validation and refresh failed. */\n session: SessionData | null;\n /** Freshly-issued token bundle when a refresh actually occurred. */\n tokens: IssuedTokens | null;\n /** True if this call rotated the refresh token. */\n refreshed: boolean;\n}\n\n/**\n * Validate the access token and, if invalid/missing, transparently rotate the\n * refresh token to obtain a new session. Framework-agnostic — used by the\n * Next.js middleware/server helpers and intended for consumption from API\n * server middleware (tRPC, Hono, plain route handlers, …).\n *\n * Cookies are NOT touched here; the caller decides how to surface the new\n * token bundle (Set-Cookie headers, in-memory store, etc.).\n *\n * Returns:\n * - `session` the resolved session (or `null`),\n * - `tokens` the newly-issued token bundle when a refresh occurred,\n * - `refreshed` whether rotation happened.\n *\n * @example\n * ```ts\n * const { session, tokens } = await getSessionOrRefresh(auth, {\n * accessToken: req.cookies.get('holeauth.at')?.value,\n * refreshToken: req.cookies.get('holeauth.rt')?.value,\n * ip, userAgent,\n * });\n * if (tokens) writeAuthCookies(auth.config, res.headers, tokens);\n * ```\n */\nexport async function getSessionOrRefresh(\n instance: HoleauthInstance,\n input: GetSessionOrRefreshInput,\n): Promise<GetSessionOrRefreshResult> {\n const { accessToken, refreshToken, ip, userAgent } = input;\n\n // 1. Fast path: valid access token.\n if (accessToken) {\n const session = await validateSession(instance.config, accessToken);\n if (session && session.expiresAt > Date.now()) {\n return { session, tokens: null, refreshed: false };\n }\n }\n\n // 2. Refresh fallback.\n if (!refreshToken) {\n return { session: null, tokens: null, refreshed: false };\n }\n\n let tokens: IssuedTokens;\n try {\n tokens = await instance.refresh({ refreshToken, ip, userAgent });\n } catch {\n // Reuse, expiry, malformed — caller should clear cookies.\n return { session: null, tokens: null, refreshed: false };\n }\n\n const session = await validateSession(instance.config, tokens.accessToken);\n return { session, tokens, refreshed: true };\n}\n"]}
1
+ {"version":3,"sources":["../../src/errors/index.ts","../../src/jwt/index.ts","../../src/cookies/csrf.ts","../../src/events/emitter.ts","../../src/plugins/runner-ref.ts","../../src/session/hash.ts","../../src/session/issue.ts","../../src/session/rotate.ts","../../src/session/validate.ts","../../src/session/revoke.ts","../../src/session/get-or-refresh.ts","../../src/cookies/spec.ts","../../src/session/request.ts"],"names":["ACCESS_DEFAULT","REFRESH_DEFAULT","session"],"mappings":"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","file":"index.js","sourcesContent":["export class HoleauthError extends Error {\n readonly code: string;\n readonly status: number;\n constructor(code: string, message: string, status = 400) {\n super(message);\n this.name = 'HoleauthError';\n this.code = code;\n this.status = status;\n }\n}\nexport class InvalidTokenError extends HoleauthError {\n constructor(message = 'Invalid token') { super('INVALID_TOKEN', message, 401); }\n}\nexport class SessionExpiredError extends HoleauthError {\n constructor(message = 'Session expired') { super('SESSION_EXPIRED', message, 401); }\n}\nexport class AdapterError extends HoleauthError {\n constructor(message = 'Adapter error') { super('ADAPTER_ERROR', message, 500); }\n}\nexport class ProviderError extends HoleauthError {\n constructor(message = 'Provider error') { super('PROVIDER_ERROR', message, 502); }\n}\nexport class CsrfError extends HoleauthError {\n constructor(message = 'CSRF validation failed') { super('CSRF_FAILED', message, 403); }\n}\nexport class CredentialsError extends HoleauthError {\n constructor(message = 'Invalid credentials') { super('INVALID_CREDENTIALS', message, 401); }\n}\nexport class AccountConflictError extends HoleauthError {\n constructor(message = 'Account conflict') { super('ACCOUNT_CONFLICT', message, 409); }\n}\nexport class RefreshReuseError extends HoleauthError {\n constructor(message = 'Refresh token reuse detected') { super('REFRESH_REUSE', message, 401); }\n}\nexport class PendingChallengeError extends HoleauthError {\n constructor(message = 'Pending challenge required') { super('PENDING_CHALLENGE', message, 401); }\n}\nexport class RegistrationDisabledError extends HoleauthError {\n constructor(message = 'Self-registration is disabled') { super('REGISTRATION_DISABLED', message, 403); }\n}\nexport class NotSupportedError extends HoleauthError {\n constructor(message = 'Operation not supported by adapter') { super('NOT_SUPPORTED', message, 501); }\n}\n","import { SignJWT, jwtVerify, decodeJwt, type JWTPayload } from 'jose';\nimport { InvalidTokenError } from '../errors/index.js';\n\nfunction toKey(secret: string | Uint8Array): Uint8Array {\n return typeof secret === 'string' ? new TextEncoder().encode(secret) : secret;\n}\n\nexport interface SignOptions {\n issuer?: string;\n audience?: string;\n subject?: string;\n expiresIn?: string | number; // e.g. '15m' or seconds\n jti?: string;\n}\n\nexport async function sign(\n payload: JWTPayload,\n secret: string | Uint8Array,\n opts: SignOptions = {},\n): Promise<string> {\n const jwt = new SignJWT(payload).setProtectedHeader({ alg: 'HS256' }).setIssuedAt();\n if (opts.issuer) jwt.setIssuer(opts.issuer);\n if (opts.audience) jwt.setAudience(opts.audience);\n if (opts.subject) jwt.setSubject(opts.subject);\n if (opts.jti) jwt.setJti(opts.jti);\n if (opts.expiresIn !== undefined) jwt.setExpirationTime(opts.expiresIn);\n return jwt.sign(toKey(secret));\n}\n\nexport async function verify<T extends JWTPayload = JWTPayload>(\n token: string,\n secret: string | Uint8Array,\n): Promise<T> {\n try {\n const { payload } = await jwtVerify(token, toKey(secret));\n return payload as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n\nexport function decode<T extends JWTPayload = JWTPayload>(token: string): T {\n try {\n return decodeJwt(token) as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n","/**\n * Double-submit CSRF protection.\n * The cookie holeauth.csrf is readable by JS (httpOnly:false). The client\n * echoes its value in header `x-csrf-token`; the server compares the two.\n * Because cross-origin JS cannot read the cookie, an attacker cannot mint\n * a matching header, defeating the cross-site POST scenario.\n */\n\nconst b64urlChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\nexport function generateCsrfToken(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n let out = '';\n for (const b of bytes) out += b64urlChars[b % 64];\n return out;\n}\n\n/** Constant-time compare. */\nexport function verifyCsrf(cookieValue: string | undefined, headerValue: string | undefined): boolean {\n if (!cookieValue || !headerValue) return false;\n if (cookieValue.length !== headerValue.length) return false;\n let diff = 0;\n for (let i = 0; i < cookieValue.length; i++) {\n diff |= cookieValue.charCodeAt(i) ^ headerValue.charCodeAt(i);\n }\n return diff === 0;\n}\n\nexport const CSRF_HEADER = 'x-csrf-token';\n","import type { HoleauthConfig } from '../types/index.js';\nimport type { HoleauthEvent } from './types.js';\n\ntype Handler = (e: HoleauthEvent) => void | Promise<void>;\n\ninterface EventBus {\n byType: Map<string, Set<Handler>>;\n wildcard: Set<Handler>;\n}\n\nconst busByConfig = new WeakMap<HoleauthConfig, EventBus>();\n\nfunction getBus(cfg: HoleauthConfig): EventBus {\n let bus = busByConfig.get(cfg);\n if (!bus) {\n bus = { byType: new Map(), wildcard: new Set() };\n busByConfig.set(cfg, bus);\n }\n return bus;\n}\n\n/** Subscribe to an event type. Use '*' to match all events. Returns an unsubscribe fn. */\nexport function subscribe(cfg: HoleauthConfig, type: string, handler: Handler): () => void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.add(handler);\n return () => bus.wildcard.delete(handler);\n }\n let set = bus.byType.get(type);\n if (!set) {\n set = new Set();\n bus.byType.set(type, set);\n }\n set.add(handler);\n return () => set!.delete(handler);\n}\n\nexport function unsubscribe(cfg: HoleauthConfig, type: string, handler: Handler): void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.delete(handler);\n return;\n }\n bus.byType.get(type)?.delete(handler);\n}\n\n/**\n * emit() persists the event via the mandatory AuditLogAdapter and\n * additionally fans out to all subscribers (typed + wildcard) plus the\n * legacy `cfg.onEvent` hook — all fire-and-forget so business flows are\n * never blocked by observer failures.\n *\n * Callers MUST await emit(): audit persistence is a hard requirement.\n */\nexport async function emit(cfg: HoleauthConfig, event: HoleauthEvent): Promise<void> {\n const withTimestamp: HoleauthEvent = { at: new Date(), ...event };\n await cfg.adapters.auditLog.record(withTimestamp);\n\n const bus = getBus(cfg);\n const typed = bus.byType.get(withTimestamp.type);\n const fire = (h: Handler) => {\n Promise.resolve()\n .then(() => h(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n };\n if (typed) for (const h of typed) fire(h);\n for (const h of bus.wildcard) fire(h);\n\n if (cfg.onEvent) {\n Promise.resolve()\n .then(() => cfg.onEvent?.(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n }\n}\n","/**\n * Per-config hook runner attachment. Stored via WeakMap so the runner is\n * reachable from low-level helpers (session/issue, session/rotate, …)\n * without threading it through every signature.\n *\n * `defineHoleauth()` attaches the runner once at instance creation.\n */\nimport type { HoleauthConfig } from '../types/index.js';\nimport type { HookRunner } from './registry.js';\n\nconst runners = new WeakMap<HoleauthConfig, HookRunner>();\n\nexport function attachHookRunner(cfg: HoleauthConfig, runner: HookRunner): void {\n runners.set(cfg, runner);\n}\n\nconst NOOP: HookRunner = {\n async runRegisterBefore() {},\n async runRegisterAfter() {},\n async runSignInBefore() {},\n async runSignInChallenge() { return null; },\n async runSignInAfter() {},\n async runSignOutAfter() {},\n async runRefreshBefore() {},\n async runRefreshAfter() {},\n async runPasswordChangeBefore() {},\n async runPasswordChangeAfter() {},\n async runPasswordResetBefore() {},\n async runPasswordResetAfter() {},\n async runUserUpdateAfter() {},\n async runUserDeleteAfter() {},\n async runSessionIssue() {},\n async runSessionRotate() {},\n async runSessionRevoke() {},\n};\n\nexport function getHookRunner(cfg: HoleauthConfig): HookRunner {\n return runners.get(cfg) ?? NOOP;\n}\n","/** SHA-256 → base64url. Works on Node 20+ and all Edge runtimes. */\nexport async function sha256b64url(input: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));\n const bytes = new Uint8Array(buf);\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","import type { HoleauthConfig, IssuedTokens } from '../types/index.js';\nimport { sign } from '../jwt/index.js';\nimport { generateCsrfToken } from '../cookies/csrf.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\nimport { sha256b64url } from './hash.js';\n\nconst ACCESS_DEFAULT = 900; // 15m\nconst REFRESH_DEFAULT = 2592000; // 30d\n\nexport interface IssueInput {\n userId: string;\n /** Omit to start a fresh family (e.g. on a real login). */\n familyId?: string;\n ip?: string | null;\n userAgent?: string | null;\n}\n\n/**\n * Mint a brand new session row + JWT pair + CSRF token.\n * Used by: fresh login, passkey login, SSO callback, 2FA verify.\n */\nexport async function issueSession(cfg: HoleauthConfig, input: IssueInput): Promise<IssuedTokens> {\n const accessTtl = cfg.tokens?.accessTtl ?? ACCESS_DEFAULT;\n const refreshTtl = cfg.tokens?.refreshTtl ?? REFRESH_DEFAULT;\n const now = Math.floor(Date.now() / 1000);\n\n const familyId = input.familyId ?? crypto.randomUUID();\n const sessionId = crypto.randomUUID();\n const nonce = crypto.randomUUID();\n\n const [accessToken, refreshToken] = await Promise.all([\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${accessTtl}s` },\n ),\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, typ: 'refresh', nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${refreshTtl}s`, jti: nonce },\n ),\n ]);\n const refreshTokenHash = await sha256b64url(refreshToken);\n\n await cfg.adapters.session.createSession({\n id: sessionId,\n userId: input.userId,\n familyId,\n refreshTokenHash,\n expiresAt: new Date((now + refreshTtl) * 1000),\n createdAt: new Date(),\n revokedAt: null,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n });\n\n const csrfToken = generateCsrfToken();\n\n await emit(cfg, {\n type: 'session.created',\n userId: input.userId,\n sessionId,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n data: { familyId },\n });\n await getHookRunner(cfg).runSessionIssue({ userId: input.userId, sessionId, familyId });\n\n return {\n accessToken,\n refreshToken,\n csrfToken,\n sessionId,\n familyId,\n accessExpiresAt: (now + accessTtl) * 1000,\n refreshExpiresAt: (now + refreshTtl) * 1000,\n };\n}\n","import type { HoleauthConfig, IssuedTokens } from '../types/index.js';\nimport { sign, verify } from '../jwt/index.js';\nimport { generateCsrfToken } from '../cookies/csrf.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\nimport { sha256b64url } from './hash.js';\nimport { InvalidTokenError, RefreshReuseError, SessionExpiredError } from '../errors/index.js';\n\nconst ACCESS_DEFAULT = 900;\nconst REFRESH_DEFAULT = 2592000;\n\n/**\n * Rotate-on-use with reuse detection.\n *\n * 1. Decode refresh JWT → recover sid, fam, sub.\n * 2. Hash presented token; look it up.\n * - If not found, the token was already rotated away → reuse! Revoke family.\n * 3. Issue new access + refresh, rotate hash in storage atomically.\n *\n * Returns a fresh IssuedTokens tuple. Session id + family stay stable.\n */\nexport async function rotateRefresh(\n cfg: HoleauthConfig,\n presentedRefresh: string,\n meta: { ip?: string | null; userAgent?: string | null } = {},\n): Promise<IssuedTokens> {\n let claims: { sid?: string; sub?: string; fam?: string; typ?: string; exp?: number };\n try {\n claims = await verify(presentedRefresh, cfg.secrets.jwtSecret);\n } catch {\n throw new InvalidTokenError('refresh token invalid');\n }\n if (claims.typ !== 'refresh' || !claims.sid || !claims.sub || !claims.fam) {\n throw new InvalidTokenError('refresh claims malformed');\n }\n\n const presentedHash = await sha256b64url(presentedRefresh);\n const found = await cfg.adapters.session.getByRefreshHash(presentedHash);\n\n if (!found || found.revokedAt) {\n // Reuse detected — revoke whole family, record an event, throw.\n await cfg.adapters.session.revokeFamily(claims.fam);\n await emit(cfg, {\n type: 'session.reuse_detected',\n userId: claims.sub,\n sessionId: claims.sid,\n ip: meta.ip ?? null,\n userAgent: meta.userAgent ?? null,\n data: { familyId: claims.fam },\n });\n throw new RefreshReuseError();\n }\n\n if (found.expiresAt.getTime() < Date.now()) {\n await cfg.adapters.session.revokeFamily(claims.fam);\n throw new SessionExpiredError();\n }\n\n const accessTtl = cfg.tokens?.accessTtl ?? ACCESS_DEFAULT;\n const refreshTtl = cfg.tokens?.refreshTtl ?? REFRESH_DEFAULT;\n const now = Math.floor(Date.now() / 1000);\n const nonce = crypto.randomUUID();\n\n const [accessToken, refreshToken] = await Promise.all([\n sign(\n { sid: found.id, sub: found.userId, fam: found.familyId, nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${accessTtl}s` },\n ),\n sign(\n { sid: found.id, sub: found.userId, fam: found.familyId, typ: 'refresh', nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${refreshTtl}s`, jti: nonce },\n ),\n ]);\n const newHash = await sha256b64url(refreshToken);\n await cfg.adapters.session.rotateRefresh(\n found.id,\n newHash,\n new Date((now + refreshTtl) * 1000),\n );\n\n await emit(cfg, {\n type: 'session.rotated',\n userId: found.userId,\n sessionId: found.id,\n ip: meta.ip ?? null,\n userAgent: meta.userAgent ?? null,\n data: { familyId: found.familyId },\n });\n await getHookRunner(cfg).runSessionRotate({\n userId: found.userId,\n sessionId: found.id,\n familyId: found.familyId,\n });\n\n return {\n accessToken,\n refreshToken,\n csrfToken: generateCsrfToken(),\n sessionId: found.id,\n familyId: found.familyId,\n accessExpiresAt: (now + accessTtl) * 1000,\n refreshExpiresAt: (now + refreshTtl) * 1000,\n };\n}\n","import type { HoleauthConfig, SessionData } from '../types/index.js';\nimport { verify } from '../jwt/index.js';\n\n/**\n * Edge-compatible: verifies the access JWT only. Does not touch adapters.\n * Use this in middleware / hot paths.\n */\nexport async function validateSession(cfg: HoleauthConfig, token: string): Promise<SessionData | null> {\n try {\n const p = await verify<{ sid: string; sub: string; fam?: string; exp?: number }>(\n token,\n cfg.secrets.jwtSecret,\n );\n if (!p.sid || !p.sub) return null;\n return {\n sessionId: p.sid,\n userId: p.sub,\n expiresAt: (p.exp ?? 0) * 1000,\n familyId: p.fam,\n };\n } catch {\n return null;\n }\n}\n","import type { HoleauthConfig } from '../types/index.js';\nimport { verify } from '../jwt/index.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\n\n/** Revoke a single session by id (signout). */\nexport async function revokeSession(cfg: HoleauthConfig, sessionId: string, userId?: string): Promise<void> {\n await cfg.adapters.session.deleteSession(sessionId);\n await emit(cfg, {\n type: 'session.revoked',\n userId: userId ?? null,\n sessionId,\n });\n await getHookRunner(cfg).runSessionRevoke({ userId: userId ?? null, sessionId });\n}\n\n/** Revoke by presented refresh token (best-effort). */\nexport async function revokeByRefresh(cfg: HoleauthConfig, refreshToken: string): Promise<void> {\n try {\n const p = await verify<{ sid?: string; sub?: string }>(refreshToken, cfg.secrets.jwtSecret);\n if (p.sid) {\n await cfg.adapters.session.deleteSession(p.sid);\n await emit(cfg, { type: 'session.revoked', userId: p.sub ?? null, sessionId: p.sid });\n await getHookRunner(cfg).runSessionRevoke({ userId: p.sub ?? null, sessionId: p.sid });\n }\n } catch { /* ignore */ }\n}\n\n/** Global signout — all sessions for a user. */\nexport async function revokeAllForUser(cfg: HoleauthConfig, userId: string): Promise<void> {\n if (cfg.adapters.session.revokeUser) {\n await cfg.adapters.session.revokeUser(userId);\n await emit(cfg, { type: 'session.revoked', userId, data: { scope: 'all' } });\n await getHookRunner(cfg).runSessionRevoke({ userId, sessionId: null, scope: 'all' });\n }\n}\n","import type {\n HoleauthInstance,\n IssuedTokens,\n SessionData,\n} from '../types/index.js';\nimport { validateSession } from './validate.js';\n\nexport interface GetSessionOrRefreshInput {\n /** Current access token (if any). */\n accessToken?: string | null;\n /** Current refresh token (if any). When present, used to rotate on access miss. */\n refreshToken?: string | null;\n /** Request metadata, forwarded to refresh hooks/audit log. */\n ip?: string;\n userAgent?: string;\n}\n\nexport interface GetSessionOrRefreshResult {\n /** Resolved session, or null if both validation and refresh failed. */\n session: SessionData | null;\n /** Freshly-issued token bundle when a refresh actually occurred. */\n tokens: IssuedTokens | null;\n /** True if this call rotated the refresh token. */\n refreshed: boolean;\n}\n\n/**\n * Validate the access token and, if invalid/missing, transparently rotate the\n * refresh token to obtain a new session. Framework-agnostic — used by the\n * Next.js middleware/server helpers and intended for consumption from API\n * server middleware (tRPC, Hono, plain route handlers, …).\n *\n * Cookies are NOT touched here; the caller decides how to surface the new\n * token bundle (Set-Cookie headers, in-memory store, etc.).\n *\n * Returns:\n * - `session` the resolved session (or `null`),\n * - `tokens` the newly-issued token bundle when a refresh occurred,\n * - `refreshed` whether rotation happened.\n *\n * @example\n * ```ts\n * const { session, tokens } = await getSessionOrRefresh(auth, {\n * accessToken: req.cookies.get('holeauth.at')?.value,\n * refreshToken: req.cookies.get('holeauth.rt')?.value,\n * ip, userAgent,\n * });\n * if (tokens) writeAuthCookies(auth.config, res.headers, tokens);\n * ```\n */\nexport async function getSessionOrRefresh(\n instance: HoleauthInstance,\n input: GetSessionOrRefreshInput,\n): Promise<GetSessionOrRefreshResult> {\n const { accessToken, refreshToken, ip, userAgent } = input;\n\n // 1. Fast path: valid access token.\n if (accessToken) {\n const session = await validateSession(instance.config, accessToken);\n if (session && session.expiresAt > Date.now()) {\n return { session, tokens: null, refreshed: false };\n }\n }\n\n // 2. Refresh fallback.\n if (!refreshToken) {\n return { session: null, tokens: null, refreshed: false };\n }\n\n let tokens: IssuedTokens;\n try {\n tokens = await instance.refresh({ refreshToken, ip, userAgent });\n } catch {\n // Reuse, expiry, malformed — caller should clear cookies.\n return { session: null, tokens: null, refreshed: false };\n }\n\n const session = await validateSession(instance.config, tokens.accessToken);\n return { session, tokens, refreshed: true };\n}\n","import type { HoleauthConfig } from '../types/index.js';\n\nexport interface CookieSpec {\n name: string;\n value: string;\n maxAge?: number; // seconds; 0 means delete\n httpOnly: boolean;\n secure: boolean;\n sameSite: 'lax' | 'strict' | 'none';\n path: string;\n domain?: string;\n}\n\nexport type CookieName = 'access' | 'refresh' | 'csrf' | 'pending' | 'oauthState' | 'oauthPkce';\n\nexport function cookieName(cfg: HoleauthConfig, kind: CookieName): string {\n const prefix = cfg.tokens?.cookiePrefix ?? 'holeauth';\n switch (kind) {\n case 'access': return `${prefix}.at`;\n case 'refresh': return `${prefix}.rt`;\n case 'csrf': return `${prefix}.csrf`;\n case 'pending': return `${prefix}.pending`;\n case 'oauthState': return `${prefix}.oauth.state`;\n case 'oauthPkce': return `${prefix}.oauth.pkce`;\n }\n}\n\nexport function isProduction(): boolean {\n return (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV === 'production';\n}\n\nexport interface BuildCookieInput {\n kind: CookieName;\n value: string;\n maxAge?: number; // seconds; 0 deletes\n /** CSRF is readable by JS — everything else is httpOnly. */\n httpOnly?: boolean;\n /** Override SameSite for the OAuth hop. */\n sameSite?: 'lax' | 'strict' | 'none';\n path?: string;\n}\n\nexport function buildCookie(cfg: HoleauthConfig, input: BuildCookieInput): CookieSpec {\n const httpOnly = input.httpOnly ?? input.kind !== 'csrf';\n const secure = cfg.tokens?.cookieSecure ?? isProduction();\n return {\n name: cookieName(cfg, input.kind),\n value: input.value,\n maxAge: input.maxAge,\n httpOnly,\n secure,\n sameSite: input.sameSite ?? cfg.tokens?.sameSite ?? 'lax',\n path: input.path ?? '/',\n domain: cfg.tokens?.cookieDomain,\n };\n}\n\n/** RFC 6265 serialisation used by Set-Cookie headers. */\nexport function serializeCookie(c: CookieSpec): string {\n const parts = [`${c.name}=${encodeURIComponent(c.value)}`];\n parts.push(`Path=${c.path}`);\n if (c.domain) parts.push(`Domain=${c.domain}`);\n if (c.maxAge !== undefined) {\n parts.push(`Max-Age=${c.maxAge}`);\n if (c.maxAge === 0) parts.push('Expires=Thu, 01 Jan 1970 00:00:00 GMT');\n }\n if (c.httpOnly) parts.push('HttpOnly');\n if (c.secure) parts.push('Secure');\n parts.push(`SameSite=${c.sameSite.charAt(0).toUpperCase()}${c.sameSite.slice(1)}`);\n return parts.join('; ');\n}\n\nexport function deleteCookie(cfg: HoleauthConfig, kind: CookieName): CookieSpec {\n return buildCookie(cfg, { kind, value: '', maxAge: 0 });\n}\n","import type { HoleauthConfig, HoleauthInstance, IssuedTokens, SessionData } from '../types/index.js';\nimport { cookieName, buildCookie, serializeCookie } from '../cookies/spec.js';\nimport { getSessionOrRefresh as coreGetSessionOrRefresh } from './get-or-refresh.js';\n\nexport interface RequestRefreshResult {\n /** Resolved session, or null if both validation and refresh failed. */\n session: SessionData | null;\n /** Freshly-issued token bundle when a refresh occurred; null otherwise. */\n tokens: IssuedTokens | null;\n /** True when the refresh token was rotated. */\n refreshed: boolean;\n /**\n * Ready-to-forward `Set-Cookie` header values. Empty when no rotation\n * occurred. The caller must append these to its outgoing response.\n */\n setCookieHeaders: string[];\n}\n\n/** Parse a raw Cookie header string into a name→value map. */\nfunction parseCookies(header: string | null): Record<string, string> {\n const out: Record<string, string> = {};\n if (!header) return out;\n for (const part of header.split(';')) {\n const i = part.indexOf('=');\n if (i < 0) continue;\n const k = part.slice(0, i).trim();\n const v = decodeURIComponent(part.slice(i + 1).trim());\n if (k) out[k] = v;\n }\n return out;\n}\n\n/** Serialize a freshly-issued token bundle into `Set-Cookie` strings. */\nfunction buildSetCookieHeaders(cfg: HoleauthConfig, tokens: IssuedTokens): string[] {\n const accessTtl = cfg.tokens?.accessTtl ?? 900;\n const refreshTtl = cfg.tokens?.refreshTtl ?? 2592000;\n return [\n serializeCookie(buildCookie(cfg, { kind: 'access', value: tokens.accessToken, maxAge: accessTtl })),\n serializeCookie(buildCookie(cfg, { kind: 'refresh', value: tokens.refreshToken, maxAge: refreshTtl })),\n serializeCookie(buildCookie(cfg, { kind: 'csrf', value: tokens.csrfToken, maxAge: refreshTtl, httpOnly: false })),\n ];\n}\n\n/**\n * Read cookies from a Web API `Request`, validate the access token, and\n * transparently rotate the refresh token when needed.\n *\n * **Framework-agnostic** — works wherever the Web Fetch `Request` type is\n * available: Next.js App Router route handlers, Hono, plain `fetch` handlers,\n * tRPC fetch adapters, Cloudflare Workers, Deno, etc.\n *\n * The caller is responsible for forwarding `setCookieHeaders` on the response\n * when the result's `refreshed` flag is `true`.\n *\n * @example tRPC context (fetch adapter)\n * ```ts\n * import { getSessionOrRefreshFromRequest } from '@holeauth/core/session';\n *\n * export const createTrpcContext = createHoleauthContext(auth);\n * // internally calls getSessionOrRefreshFromRequest(req, auth)\n * ```\n *\n * @example Manual use in a route handler\n * ```ts\n * const { session, setCookieHeaders } = await getSessionOrRefreshFromRequest(req, auth);\n * for (const c of setCookieHeaders) resHeaders.append('Set-Cookie', c);\n * ```\n */\nexport async function getSessionOrRefreshFromRequest(\n req: Request,\n instance: HoleauthInstance,\n): Promise<RequestRefreshResult> {\n const cfg = instance.config;\n const jar = parseCookies(req.headers.get('cookie'));\n const accessToken = jar[cookieName(cfg, 'access')];\n const refreshToken = jar[cookieName(cfg, 'refresh')];\n\n const ip =\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??\n req.headers.get('x-real-ip') ??\n undefined;\n const userAgent = req.headers.get('user-agent') ?? undefined;\n\n const result = await coreGetSessionOrRefresh(instance, {\n accessToken,\n refreshToken,\n ip,\n userAgent,\n });\n\n const setCookieHeaders = result.tokens ? buildSetCookieHeaders(cfg, result.tokens) : [];\n\n return { ...result, setCookieHeaders };\n}\n"]}
@@ -1,3 +1,3 @@
1
- export { A as AuthorizeParams, G as GithubProvider, a as GoogleProvider, T as TokenExchangeInput, b as authorize, c as base64url, d as buildAuthorizeUrl, e as callback, f as exchangeCode, g as fetchUserInfo, h as findProvider, j as generateNonce, k as generatePkcePair, l as generateState } from '../index-CHS-socJ.js';
2
- import '../index-BmYQquGs.js';
1
+ export { A as AuthorizeParams, D as DiscordProvider, G as GithubProvider, a as GoogleProvider, M as MicrosoftProvider, O as OIDCProvider, T as TokenExchangeInput, b as authorize, c as base64url, d as buildAuthorizeUrl, e as callback, f as exchangeCode, g as fetchUserInfo, h as findProvider, j as generateNonce, k as generatePkcePair, l as generateState } from '../index-CcMMWIEe.js';
2
+ import '../index-Bt3CyLaq.js';
3
3
  import '../index-CNtnPdzk.js';
package/dist/sso/index.js CHANGED
@@ -470,6 +470,69 @@ function GithubProvider(opts) {
470
470
  };
471
471
  }
472
472
 
473
- export { GithubProvider, GoogleProvider, authorize, base64url, buildAuthorizeUrl, callback, exchangeCode, fetchUserInfo, findProvider, generateNonce, generatePkcePair, generateState };
473
+ // src/sso/providers/discord.ts
474
+ function DiscordProvider(opts) {
475
+ return {
476
+ kind: "oauth2",
477
+ id: opts.id ?? "discord",
478
+ name: "Discord",
479
+ clientId: opts.clientId,
480
+ clientSecret: opts.clientSecret,
481
+ redirectUri: opts.redirectUri,
482
+ scopes: opts.scopes ?? ["identify", "email"],
483
+ authorizationUrl: "https://discord.com/oauth2/authorize",
484
+ tokenUrl: "https://discord.com/api/oauth2/token",
485
+ userinfoUrl: "https://discord.com/api/users/@me",
486
+ profile: (raw) => {
487
+ const p = raw ?? {};
488
+ const id = String(p.id ?? "");
489
+ const image = id && p.avatar ? `https://cdn.discordapp.com/avatars/${id}/${p.avatar}.png` : null;
490
+ return {
491
+ providerAccountId: id,
492
+ email: p.email ?? "",
493
+ name: p.global_name ?? p.username ?? null,
494
+ image
495
+ };
496
+ }
497
+ };
498
+ }
499
+
500
+ // src/sso/providers/microsoft.ts
501
+ function MicrosoftProvider(opts) {
502
+ const tenant = opts.tenantId ?? "common";
503
+ const base = `https://login.microsoftonline.com/${tenant}`;
504
+ return {
505
+ kind: "oidc",
506
+ id: opts.id ?? "microsoft",
507
+ name: "Microsoft",
508
+ clientId: opts.clientId,
509
+ clientSecret: opts.clientSecret,
510
+ redirectUri: opts.redirectUri,
511
+ scopes: opts.scopes ?? ["openid", "email", "profile"],
512
+ issuer: `${base}/v2.0`,
513
+ authorizationUrl: `${base}/oauth2/v2.0/authorize`,
514
+ tokenUrl: `${base}/oauth2/v2.0/token`,
515
+ userinfoUrl: "https://graph.microsoft.com/oidc/userinfo"
516
+ };
517
+ }
518
+
519
+ // src/sso/providers/oidc.ts
520
+ function OIDCProvider(opts) {
521
+ return {
522
+ kind: "oidc",
523
+ id: opts.id,
524
+ name: opts.name ?? opts.id,
525
+ clientId: opts.clientId,
526
+ clientSecret: opts.clientSecret,
527
+ redirectUri: opts.redirectUri,
528
+ scopes: opts.scopes ?? ["openid", "email", "profile"],
529
+ issuer: opts.issuer,
530
+ authorizationUrl: opts.authorizationUrl,
531
+ tokenUrl: opts.tokenUrl,
532
+ userinfoUrl: opts.userinfoUrl
533
+ };
534
+ }
535
+
536
+ export { DiscordProvider, GithubProvider, GoogleProvider, MicrosoftProvider, OIDCProvider, authorize, base64url, buildAuthorizeUrl, callback, exchangeCode, fetchUserInfo, findProvider, generateNonce, generatePkcePair, generateState };
474
537
  //# sourceMappingURL=index.js.map
475
538
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors/index.ts","../../src/sso/client.ts","../../src/events/emitter.ts","../../src/sso/authorize.ts","../../src/jwt/index.ts","../../src/cookies/csrf.ts","../../src/plugins/runner-ref.ts","../../src/session/hash.ts","../../src/session/issue.ts","../../src/sso/callback.ts","../../src/sso/providers/google.ts","../../src/sso/providers/github.ts"],"names":["email"],"mappings":"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","file":"index.js","sourcesContent":["export class HoleauthError extends Error {\n readonly code: string;\n readonly status: number;\n constructor(code: string, message: string, status = 400) {\n super(message);\n this.name = 'HoleauthError';\n this.code = code;\n this.status = status;\n }\n}\nexport class InvalidTokenError extends HoleauthError {\n constructor(message = 'Invalid token') { super('INVALID_TOKEN', message, 401); }\n}\nexport class SessionExpiredError extends HoleauthError {\n constructor(message = 'Session expired') { super('SESSION_EXPIRED', message, 401); }\n}\nexport class AdapterError extends HoleauthError {\n constructor(message = 'Adapter error') { super('ADAPTER_ERROR', message, 500); }\n}\nexport class ProviderError extends HoleauthError {\n constructor(message = 'Provider error') { super('PROVIDER_ERROR', message, 502); }\n}\nexport class CsrfError extends HoleauthError {\n constructor(message = 'CSRF validation failed') { super('CSRF_FAILED', message, 403); }\n}\nexport class CredentialsError extends HoleauthError {\n constructor(message = 'Invalid credentials') { super('INVALID_CREDENTIALS', message, 401); }\n}\nexport class AccountConflictError extends HoleauthError {\n constructor(message = 'Account conflict') { super('ACCOUNT_CONFLICT', message, 409); }\n}\nexport class RefreshReuseError extends HoleauthError {\n constructor(message = 'Refresh token reuse detected') { super('REFRESH_REUSE', message, 401); }\n}\nexport class PendingChallengeError extends HoleauthError {\n constructor(message = 'Pending challenge required') { super('PENDING_CHALLENGE', message, 401); }\n}\nexport class RegistrationDisabledError extends HoleauthError {\n constructor(message = 'Self-registration is disabled') { super('REGISTRATION_DISABLED', message, 403); }\n}\nexport class NotSupportedError extends HoleauthError {\n constructor(message = 'Operation not supported by adapter') { super('NOT_SUPPORTED', message, 501); }\n}\n","/**\n * Generic OAuth2/OIDC PKCE client helpers.\n * High-level per-provider flows live in ./authorize.ts and ./callback.ts.\n */\nimport { ProviderError } from '../errors/index.js';\n\nexport interface AuthorizeParams {\n issuerAuthUrl: string;\n clientId: string;\n redirectUri: string;\n scopes?: string[];\n state: string;\n codeChallenge: string;\n nonce?: string;\n /** Extra params merged into the query string. */\n extra?: Record<string, string>;\n}\n\nexport function buildAuthorizeUrl(p: AuthorizeParams): string {\n const url = new URL(p.issuerAuthUrl);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('client_id', p.clientId);\n url.searchParams.set('redirect_uri', p.redirectUri);\n url.searchParams.set('scope', (p.scopes ?? ['openid', 'email', 'profile']).join(' '));\n url.searchParams.set('state', p.state);\n url.searchParams.set('code_challenge', p.codeChallenge);\n url.searchParams.set('code_challenge_method', 'S256');\n if (p.nonce) url.searchParams.set('nonce', p.nonce);\n for (const [k, v] of Object.entries(p.extra ?? {})) url.searchParams.set(k, v);\n return url.toString();\n}\n\nexport async function generatePkcePair(): Promise<{ verifier: string; challenge: string }> {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n const verifier = base64url(bytes);\n const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));\n return { verifier, challenge: base64url(new Uint8Array(hash)) };\n}\n\nexport function generateState(): string {\n return base64url(crypto.getRandomValues(new Uint8Array(16)));\n}\n\nexport function generateNonce(): string {\n return base64url(crypto.getRandomValues(new Uint8Array(16)));\n}\n\nexport interface TokenExchangeInput {\n tokenUrl: string;\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n code: string;\n codeVerifier: string;\n}\n\nexport async function exchangeCode(i: TokenExchangeInput): Promise<Record<string, unknown>> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code: i.code,\n redirect_uri: i.redirectUri,\n client_id: i.clientId,\n client_secret: i.clientSecret,\n code_verifier: i.codeVerifier,\n });\n const res = await fetch(i.tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },\n body,\n });\n if (!res.ok) throw new ProviderError(`Token exchange failed: ${res.status}`);\n return (await res.json()) as Record<string, unknown>;\n}\n\nexport async function fetchUserInfo(\n userinfoUrl: string,\n accessToken: string,\n): Promise<Record<string, unknown>> {\n const res = await fetch(userinfoUrl, {\n headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json' },\n });\n if (!res.ok) throw new ProviderError(`Userinfo failed: ${res.status}`);\n return (await res.json()) as Record<string, unknown>;\n}\n\nexport function base64url(bytes: Uint8Array): string {\n let s = ''; for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","import type { HoleauthConfig } from '../types/index.js';\nimport type { HoleauthEvent } from './types.js';\n\ntype Handler = (e: HoleauthEvent) => void | Promise<void>;\n\ninterface EventBus {\n byType: Map<string, Set<Handler>>;\n wildcard: Set<Handler>;\n}\n\nconst busByConfig = new WeakMap<HoleauthConfig, EventBus>();\n\nfunction getBus(cfg: HoleauthConfig): EventBus {\n let bus = busByConfig.get(cfg);\n if (!bus) {\n bus = { byType: new Map(), wildcard: new Set() };\n busByConfig.set(cfg, bus);\n }\n return bus;\n}\n\n/** Subscribe to an event type. Use '*' to match all events. Returns an unsubscribe fn. */\nexport function subscribe(cfg: HoleauthConfig, type: string, handler: Handler): () => void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.add(handler);\n return () => bus.wildcard.delete(handler);\n }\n let set = bus.byType.get(type);\n if (!set) {\n set = new Set();\n bus.byType.set(type, set);\n }\n set.add(handler);\n return () => set!.delete(handler);\n}\n\nexport function unsubscribe(cfg: HoleauthConfig, type: string, handler: Handler): void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.delete(handler);\n return;\n }\n bus.byType.get(type)?.delete(handler);\n}\n\n/**\n * emit() persists the event via the mandatory AuditLogAdapter and\n * additionally fans out to all subscribers (typed + wildcard) plus the\n * legacy `cfg.onEvent` hook — all fire-and-forget so business flows are\n * never blocked by observer failures.\n *\n * Callers MUST await emit(): audit persistence is a hard requirement.\n */\nexport async function emit(cfg: HoleauthConfig, event: HoleauthEvent): Promise<void> {\n const withTimestamp: HoleauthEvent = { at: new Date(), ...event };\n await cfg.adapters.auditLog.record(withTimestamp);\n\n const bus = getBus(cfg);\n const typed = bus.byType.get(withTimestamp.type);\n const fire = (h: Handler) => {\n Promise.resolve()\n .then(() => h(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n };\n if (typed) for (const h of typed) fire(h);\n for (const h of bus.wildcard) fire(h);\n\n if (cfg.onEvent) {\n Promise.resolve()\n .then(() => cfg.onEvent?.(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n }\n}\n","import type { HoleauthConfig, ProviderConfig } from '../types/index.js';\nimport { ProviderError } from '../errors/index.js';\nimport { buildAuthorizeUrl, generatePkcePair, generateState, generateNonce } from './client.js';\nimport { emit } from '../events/emitter.js';\n\nexport function findProvider(cfg: HoleauthConfig, id: string): ProviderConfig {\n const p = cfg.providers?.find((x) => x.id === id);\n if (!p) throw new ProviderError(`unknown provider: ${id}`);\n return p;\n}\n\n/**\n * Begin the SSO hop. Returns a URL to redirect the user to, plus state +\n * PKCE verifier the caller must persist (typically in httpOnly cookies)\n * to validate the callback.\n */\nexport async function authorize(\n cfg: HoleauthConfig,\n providerId: string,\n): Promise<{ url: string; state: string; codeVerifier: string; nonce?: string }> {\n const p = findProvider(cfg, providerId);\n const state = generateState();\n const { verifier, challenge } = await generatePkcePair();\n const nonce = p.kind === 'oidc' ? generateNonce() : undefined;\n\n const url = buildAuthorizeUrl({\n issuerAuthUrl: p.authorizationUrl,\n clientId: p.clientId,\n redirectUri: p.redirectUri,\n scopes: p.scopes,\n state,\n codeChallenge: challenge,\n nonce,\n });\n\n await emit(cfg, { type: 'sso.authorize', data: { provider: providerId } });\n return { url, state, codeVerifier: verifier, nonce };\n}\n","import { SignJWT, jwtVerify, decodeJwt, type JWTPayload } from 'jose';\nimport { InvalidTokenError } from '../errors/index.js';\n\nfunction toKey(secret: string | Uint8Array): Uint8Array {\n return typeof secret === 'string' ? new TextEncoder().encode(secret) : secret;\n}\n\nexport interface SignOptions {\n issuer?: string;\n audience?: string;\n subject?: string;\n expiresIn?: string | number; // e.g. '15m' or seconds\n jti?: string;\n}\n\nexport async function sign(\n payload: JWTPayload,\n secret: string | Uint8Array,\n opts: SignOptions = {},\n): Promise<string> {\n const jwt = new SignJWT(payload).setProtectedHeader({ alg: 'HS256' }).setIssuedAt();\n if (opts.issuer) jwt.setIssuer(opts.issuer);\n if (opts.audience) jwt.setAudience(opts.audience);\n if (opts.subject) jwt.setSubject(opts.subject);\n if (opts.jti) jwt.setJti(opts.jti);\n if (opts.expiresIn !== undefined) jwt.setExpirationTime(opts.expiresIn);\n return jwt.sign(toKey(secret));\n}\n\nexport async function verify<T extends JWTPayload = JWTPayload>(\n token: string,\n secret: string | Uint8Array,\n): Promise<T> {\n try {\n const { payload } = await jwtVerify(token, toKey(secret));\n return payload as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n\nexport function decode<T extends JWTPayload = JWTPayload>(token: string): T {\n try {\n return decodeJwt(token) as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n","/**\n * Double-submit CSRF protection.\n * The cookie holeauth.csrf is readable by JS (httpOnly:false). The client\n * echoes its value in header `x-csrf-token`; the server compares the two.\n * Because cross-origin JS cannot read the cookie, an attacker cannot mint\n * a matching header, defeating the cross-site POST scenario.\n */\n\nconst b64urlChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\nexport function generateCsrfToken(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n let out = '';\n for (const b of bytes) out += b64urlChars[b % 64];\n return out;\n}\n\n/** Constant-time compare. */\nexport function verifyCsrf(cookieValue: string | undefined, headerValue: string | undefined): boolean {\n if (!cookieValue || !headerValue) return false;\n if (cookieValue.length !== headerValue.length) return false;\n let diff = 0;\n for (let i = 0; i < cookieValue.length; i++) {\n diff |= cookieValue.charCodeAt(i) ^ headerValue.charCodeAt(i);\n }\n return diff === 0;\n}\n\nexport const CSRF_HEADER = 'x-csrf-token';\n","/**\n * Per-config hook runner attachment. Stored via WeakMap so the runner is\n * reachable from low-level helpers (session/issue, session/rotate, …)\n * without threading it through every signature.\n *\n * `defineHoleauth()` attaches the runner once at instance creation.\n */\nimport type { HoleauthConfig } from '../types/index.js';\nimport type { HookRunner } from './registry.js';\n\nconst runners = new WeakMap<HoleauthConfig, HookRunner>();\n\nexport function attachHookRunner(cfg: HoleauthConfig, runner: HookRunner): void {\n runners.set(cfg, runner);\n}\n\nconst NOOP: HookRunner = {\n async runRegisterBefore() {},\n async runRegisterAfter() {},\n async runSignInBefore() {},\n async runSignInChallenge() { return null; },\n async runSignInAfter() {},\n async runSignOutAfter() {},\n async runRefreshBefore() {},\n async runRefreshAfter() {},\n async runPasswordChangeBefore() {},\n async runPasswordChangeAfter() {},\n async runPasswordResetBefore() {},\n async runPasswordResetAfter() {},\n async runUserUpdateAfter() {},\n async runUserDeleteAfter() {},\n async runSessionIssue() {},\n async runSessionRotate() {},\n async runSessionRevoke() {},\n};\n\nexport function getHookRunner(cfg: HoleauthConfig): HookRunner {\n return runners.get(cfg) ?? NOOP;\n}\n","/** SHA-256 → base64url. Works on Node 20+ and all Edge runtimes. */\nexport async function sha256b64url(input: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));\n const bytes = new Uint8Array(buf);\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","import type { HoleauthConfig, IssuedTokens } from '../types/index.js';\nimport { sign } from '../jwt/index.js';\nimport { generateCsrfToken } from '../cookies/csrf.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\nimport { sha256b64url } from './hash.js';\n\nconst ACCESS_DEFAULT = 900; // 15m\nconst REFRESH_DEFAULT = 2592000; // 30d\n\nexport interface IssueInput {\n userId: string;\n /** Omit to start a fresh family (e.g. on a real login). */\n familyId?: string;\n ip?: string | null;\n userAgent?: string | null;\n}\n\n/**\n * Mint a brand new session row + JWT pair + CSRF token.\n * Used by: fresh login, passkey login, SSO callback, 2FA verify.\n */\nexport async function issueSession(cfg: HoleauthConfig, input: IssueInput): Promise<IssuedTokens> {\n const accessTtl = cfg.tokens?.accessTtl ?? ACCESS_DEFAULT;\n const refreshTtl = cfg.tokens?.refreshTtl ?? REFRESH_DEFAULT;\n const now = Math.floor(Date.now() / 1000);\n\n const familyId = input.familyId ?? crypto.randomUUID();\n const sessionId = crypto.randomUUID();\n const nonce = crypto.randomUUID();\n\n const [accessToken, refreshToken] = await Promise.all([\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${accessTtl}s` },\n ),\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, typ: 'refresh', nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${refreshTtl}s`, jti: nonce },\n ),\n ]);\n const refreshTokenHash = await sha256b64url(refreshToken);\n\n await cfg.adapters.session.createSession({\n id: sessionId,\n userId: input.userId,\n familyId,\n refreshTokenHash,\n expiresAt: new Date((now + refreshTtl) * 1000),\n createdAt: new Date(),\n revokedAt: null,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n });\n\n const csrfToken = generateCsrfToken();\n\n await emit(cfg, {\n type: 'session.created',\n userId: input.userId,\n sessionId,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n data: { familyId },\n });\n await getHookRunner(cfg).runSessionIssue({ userId: input.userId, sessionId, familyId });\n\n return {\n accessToken,\n refreshToken,\n csrfToken,\n sessionId,\n familyId,\n accessExpiresAt: (now + accessTtl) * 1000,\n refreshExpiresAt: (now + refreshTtl) * 1000,\n };\n}\n","import type { HoleauthConfig, IssuedTokens, ProviderConfig } from '../types/index.js';\nimport type { AdapterUser } from '../adapters/index.js';\nimport { findProvider } from './authorize.js';\nimport { exchangeCode, fetchUserInfo } from './client.js';\nimport { decode } from '../jwt/index.js';\nimport { issueSession } from '../session/issue.js';\nimport { AccountConflictError, ProviderError } from '../errors/index.js';\nimport { emit } from '../events/emitter.js';\n\nexport interface CallbackInput {\n code: string;\n state: string;\n codeVerifier: string;\n ip?: string;\n userAgent?: string;\n}\n\ninterface NormalisedProfile {\n providerAccountId: string;\n email: string;\n name?: string | null;\n image?: string | null;\n emailVerified: boolean;\n}\n\nasync function exchangeAndProfile(\n p: ProviderConfig,\n input: CallbackInput,\n): Promise<{ tokens: Record<string, unknown>; profile: NormalisedProfile }> {\n const tokens = await exchangeCode({\n tokenUrl: p.tokenUrl,\n clientId: p.clientId,\n clientSecret: p.clientSecret,\n redirectUri: p.redirectUri,\n code: input.code,\n codeVerifier: input.codeVerifier,\n });\n\n const accessToken = typeof tokens.access_token === 'string' ? tokens.access_token : null;\n if (!accessToken) throw new ProviderError('no access_token in response');\n\n if (p.kind === 'oidc') {\n const idToken = typeof tokens.id_token === 'string' ? tokens.id_token : null;\n if (idToken) {\n const claims = decode<{\n sub?: string;\n email?: string;\n email_verified?: boolean;\n name?: string;\n picture?: string;\n }>(idToken);\n if (claims.sub && claims.email) {\n return {\n tokens,\n profile: {\n providerAccountId: claims.sub,\n email: claims.email.toLowerCase(),\n name: claims.name ?? null,\n image: claims.picture ?? null,\n emailVerified: claims.email_verified ?? false,\n },\n };\n }\n }\n // Fall back to userinfo\n const ui = await fetchUserInfo(p.userinfoUrl, accessToken);\n const sub = (ui.sub ?? '') as string;\n const email = typeof ui.email === 'string' ? ui.email.toLowerCase() : '';\n if (!sub || !email) throw new ProviderError('userinfo missing sub/email');\n return {\n tokens,\n profile: {\n providerAccountId: sub,\n email,\n name: (ui.name as string | null) ?? null,\n image: (ui.picture as string | null) ?? null,\n emailVerified: Boolean(ui.email_verified),\n },\n };\n }\n\n // oauth2\n const raw = await fetchUserInfo(p.userinfoUrl, accessToken);\n const mapped = p.profile(raw);\n if (!mapped.providerAccountId) throw new ProviderError('provider profile missing id');\n // GitHub may return null email — fall back to /user/emails.\n let email = mapped.email.toLowerCase();\n let verified = false;\n if (!email && p.id === 'github') {\n const emails = (await fetchUserInfo('https://api.github.com/user/emails', accessToken)) as unknown as Array<{\n email: string;\n primary: boolean;\n verified: boolean;\n }>;\n const primary = Array.isArray(emails) ? emails.find((e) => e.primary) : undefined;\n if (primary) {\n email = primary.email.toLowerCase();\n verified = primary.verified;\n }\n }\n if (!email) throw new ProviderError('provider did not return an email');\n return {\n tokens,\n profile: {\n providerAccountId: mapped.providerAccountId,\n email,\n name: mapped.name ?? null,\n image: mapped.image ?? null,\n emailVerified: verified,\n },\n };\n}\n\nasync function resolveUser(\n cfg: HoleauthConfig,\n provider: ProviderConfig,\n profile: NormalisedProfile,\n rawTokens: Record<string, unknown>,\n): Promise<AdapterUser> {\n const account = cfg.adapters.account;\n\n // 1. Try existing link\n if (account) {\n const existing = await account.getAccountByProvider(provider.id, profile.providerAccountId);\n if (existing) {\n const u = await cfg.adapters.user.getUserById(existing.userId);\n if (u) return u;\n }\n }\n\n // 2. Try user by email (potential linking)\n const byEmail = await cfg.adapters.user.getUserByEmail(profile.email);\n if (byEmail) {\n if (!cfg.allowDangerousEmailAccountLinking || !profile.emailVerified) {\n throw new AccountConflictError(\n `an account with email ${profile.email} already exists; enable allowDangerousEmailAccountLinking or sign in with password first`,\n );\n }\n // Auto-link\n if (account) {\n const linked = await account.linkAccount({\n userId: byEmail.id,\n provider: provider.id,\n providerAccountId: profile.providerAccountId,\n email: profile.email,\n accessToken: (rawTokens.access_token as string) ?? null,\n refreshToken: (rawTokens.refresh_token as string) ?? null,\n idToken: (rawTokens.id_token as string) ?? null,\n tokenType: (rawTokens.token_type as string) ?? null,\n scope: (rawTokens.scope as string) ?? null,\n expiresAt: typeof rawTokens.expires_in === 'number'\n ? new Date(Date.now() + (rawTokens.expires_in as number) * 1000)\n : null,\n });\n await emit(cfg, {\n type: 'account.linked',\n userId: byEmail.id,\n data: { provider: provider.id, accountId: linked.id, auto: true },\n });\n }\n return byEmail;\n }\n\n // 3. Create user + (maybe) link\n const user = await cfg.adapters.user.createUser({\n email: profile.email,\n name: profile.name ?? null,\n image: profile.image ?? null,\n emailVerified: profile.emailVerified ? new Date() : null,\n });\n if (account) {\n const linked = await account.linkAccount({\n userId: user.id,\n provider: provider.id,\n providerAccountId: profile.providerAccountId,\n email: profile.email,\n accessToken: (rawTokens.access_token as string) ?? null,\n refreshToken: (rawTokens.refresh_token as string) ?? null,\n idToken: (rawTokens.id_token as string) ?? null,\n tokenType: (rawTokens.token_type as string) ?? null,\n scope: (rawTokens.scope as string) ?? null,\n expiresAt: typeof rawTokens.expires_in === 'number'\n ? new Date(Date.now() + (rawTokens.expires_in as number) * 1000)\n : null,\n });\n await emit(cfg, {\n type: 'account.linked',\n userId: user.id,\n data: { provider: provider.id, accountId: linked.id, onCreate: true },\n });\n }\n return user;\n}\n\nexport async function callback(\n cfg: HoleauthConfig,\n providerId: string,\n input: CallbackInput,\n): Promise<{ user: AdapterUser; tokens: IssuedTokens }> {\n const p = findProvider(cfg, providerId);\n try {\n const { tokens: rawTokens, profile } = await exchangeAndProfile(p, input);\n const user = await resolveUser(cfg, p, profile, rawTokens);\n\n const tokens = await issueSession(cfg, {\n userId: user.id,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n });\n await emit(cfg, {\n type: 'sso.callback_ok',\n userId: user.id,\n sessionId: tokens.sessionId,\n data: { provider: providerId },\n });\n return { user, tokens };\n } catch (e) {\n await emit(cfg, {\n type: 'sso.callback_failed',\n data: { provider: providerId, error: (e as Error).message },\n });\n throw e;\n }\n}\n","import type { OIDCProviderConfig } from '../../types/index.js';\n\nexport interface GoogleOptions {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n id?: string;\n scopes?: string[];\n}\n\n/** Google OpenID Connect provider. */\nexport function GoogleProvider(opts: GoogleOptions): OIDCProviderConfig {\n return {\n kind: 'oidc',\n id: opts.id ?? 'google',\n name: 'Google',\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['openid', 'email', 'profile'],\n issuer: 'https://accounts.google.com',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n userinfoUrl: 'https://openidconnect.googleapis.com/v1/userinfo',\n };\n}\n","import type { OAuth2ProviderConfig } from '../../types/index.js';\n\nexport interface GithubOptions {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n id?: string;\n scopes?: string[];\n}\n\n/** GitHub OAuth2 provider. Uses REST userinfo (no OIDC). */\nexport function GithubProvider(opts: GithubOptions): OAuth2ProviderConfig {\n return {\n kind: 'oauth2',\n id: opts.id ?? 'github',\n name: 'GitHub',\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['read:user', 'user:email'],\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n userinfoUrl: 'https://api.github.com/user',\n profile: (raw) => {\n const p = (raw ?? {}) as {\n id?: number | string;\n login?: string;\n email?: string | null;\n name?: string | null;\n avatar_url?: string | null;\n };\n return {\n providerAccountId: String(p.id ?? p.login ?? ''),\n email: p.email ?? '',\n name: p.name ?? p.login ?? null,\n image: p.avatar_url ?? null,\n };\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/errors/index.ts","../../src/sso/client.ts","../../src/events/emitter.ts","../../src/sso/authorize.ts","../../src/jwt/index.ts","../../src/cookies/csrf.ts","../../src/plugins/runner-ref.ts","../../src/session/hash.ts","../../src/session/issue.ts","../../src/sso/callback.ts","../../src/sso/providers/google.ts","../../src/sso/providers/github.ts","../../src/sso/providers/discord.ts","../../src/sso/providers/microsoft.ts","../../src/sso/providers/oidc.ts"],"names":["email"],"mappings":"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","file":"index.js","sourcesContent":["export class HoleauthError extends Error {\n readonly code: string;\n readonly status: number;\n constructor(code: string, message: string, status = 400) {\n super(message);\n this.name = 'HoleauthError';\n this.code = code;\n this.status = status;\n }\n}\nexport class InvalidTokenError extends HoleauthError {\n constructor(message = 'Invalid token') { super('INVALID_TOKEN', message, 401); }\n}\nexport class SessionExpiredError extends HoleauthError {\n constructor(message = 'Session expired') { super('SESSION_EXPIRED', message, 401); }\n}\nexport class AdapterError extends HoleauthError {\n constructor(message = 'Adapter error') { super('ADAPTER_ERROR', message, 500); }\n}\nexport class ProviderError extends HoleauthError {\n constructor(message = 'Provider error') { super('PROVIDER_ERROR', message, 502); }\n}\nexport class CsrfError extends HoleauthError {\n constructor(message = 'CSRF validation failed') { super('CSRF_FAILED', message, 403); }\n}\nexport class CredentialsError extends HoleauthError {\n constructor(message = 'Invalid credentials') { super('INVALID_CREDENTIALS', message, 401); }\n}\nexport class AccountConflictError extends HoleauthError {\n constructor(message = 'Account conflict') { super('ACCOUNT_CONFLICT', message, 409); }\n}\nexport class RefreshReuseError extends HoleauthError {\n constructor(message = 'Refresh token reuse detected') { super('REFRESH_REUSE', message, 401); }\n}\nexport class PendingChallengeError extends HoleauthError {\n constructor(message = 'Pending challenge required') { super('PENDING_CHALLENGE', message, 401); }\n}\nexport class RegistrationDisabledError extends HoleauthError {\n constructor(message = 'Self-registration is disabled') { super('REGISTRATION_DISABLED', message, 403); }\n}\nexport class NotSupportedError extends HoleauthError {\n constructor(message = 'Operation not supported by adapter') { super('NOT_SUPPORTED', message, 501); }\n}\n","/**\n * Generic OAuth2/OIDC PKCE client helpers.\n * High-level per-provider flows live in ./authorize.ts and ./callback.ts.\n */\nimport { ProviderError } from '../errors/index.js';\n\nexport interface AuthorizeParams {\n issuerAuthUrl: string;\n clientId: string;\n redirectUri: string;\n scopes?: string[];\n state: string;\n codeChallenge: string;\n nonce?: string;\n /** Extra params merged into the query string. */\n extra?: Record<string, string>;\n}\n\nexport function buildAuthorizeUrl(p: AuthorizeParams): string {\n const url = new URL(p.issuerAuthUrl);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('client_id', p.clientId);\n url.searchParams.set('redirect_uri', p.redirectUri);\n url.searchParams.set('scope', (p.scopes ?? ['openid', 'email', 'profile']).join(' '));\n url.searchParams.set('state', p.state);\n url.searchParams.set('code_challenge', p.codeChallenge);\n url.searchParams.set('code_challenge_method', 'S256');\n if (p.nonce) url.searchParams.set('nonce', p.nonce);\n for (const [k, v] of Object.entries(p.extra ?? {})) url.searchParams.set(k, v);\n return url.toString();\n}\n\nexport async function generatePkcePair(): Promise<{ verifier: string; challenge: string }> {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n const verifier = base64url(bytes);\n const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));\n return { verifier, challenge: base64url(new Uint8Array(hash)) };\n}\n\nexport function generateState(): string {\n return base64url(crypto.getRandomValues(new Uint8Array(16)));\n}\n\nexport function generateNonce(): string {\n return base64url(crypto.getRandomValues(new Uint8Array(16)));\n}\n\nexport interface TokenExchangeInput {\n tokenUrl: string;\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n code: string;\n codeVerifier: string;\n}\n\nexport async function exchangeCode(i: TokenExchangeInput): Promise<Record<string, unknown>> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code: i.code,\n redirect_uri: i.redirectUri,\n client_id: i.clientId,\n client_secret: i.clientSecret,\n code_verifier: i.codeVerifier,\n });\n const res = await fetch(i.tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },\n body,\n });\n if (!res.ok) throw new ProviderError(`Token exchange failed: ${res.status}`);\n return (await res.json()) as Record<string, unknown>;\n}\n\nexport async function fetchUserInfo(\n userinfoUrl: string,\n accessToken: string,\n): Promise<Record<string, unknown>> {\n const res = await fetch(userinfoUrl, {\n headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json' },\n });\n if (!res.ok) throw new ProviderError(`Userinfo failed: ${res.status}`);\n return (await res.json()) as Record<string, unknown>;\n}\n\nexport function base64url(bytes: Uint8Array): string {\n let s = ''; for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","import type { HoleauthConfig } from '../types/index.js';\nimport type { HoleauthEvent } from './types.js';\n\ntype Handler = (e: HoleauthEvent) => void | Promise<void>;\n\ninterface EventBus {\n byType: Map<string, Set<Handler>>;\n wildcard: Set<Handler>;\n}\n\nconst busByConfig = new WeakMap<HoleauthConfig, EventBus>();\n\nfunction getBus(cfg: HoleauthConfig): EventBus {\n let bus = busByConfig.get(cfg);\n if (!bus) {\n bus = { byType: new Map(), wildcard: new Set() };\n busByConfig.set(cfg, bus);\n }\n return bus;\n}\n\n/** Subscribe to an event type. Use '*' to match all events. Returns an unsubscribe fn. */\nexport function subscribe(cfg: HoleauthConfig, type: string, handler: Handler): () => void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.add(handler);\n return () => bus.wildcard.delete(handler);\n }\n let set = bus.byType.get(type);\n if (!set) {\n set = new Set();\n bus.byType.set(type, set);\n }\n set.add(handler);\n return () => set!.delete(handler);\n}\n\nexport function unsubscribe(cfg: HoleauthConfig, type: string, handler: Handler): void {\n const bus = getBus(cfg);\n if (type === '*') {\n bus.wildcard.delete(handler);\n return;\n }\n bus.byType.get(type)?.delete(handler);\n}\n\n/**\n * emit() persists the event via the mandatory AuditLogAdapter and\n * additionally fans out to all subscribers (typed + wildcard) plus the\n * legacy `cfg.onEvent` hook — all fire-and-forget so business flows are\n * never blocked by observer failures.\n *\n * Callers MUST await emit(): audit persistence is a hard requirement.\n */\nexport async function emit(cfg: HoleauthConfig, event: HoleauthEvent): Promise<void> {\n const withTimestamp: HoleauthEvent = { at: new Date(), ...event };\n await cfg.adapters.auditLog.record(withTimestamp);\n\n const bus = getBus(cfg);\n const typed = bus.byType.get(withTimestamp.type);\n const fire = (h: Handler) => {\n Promise.resolve()\n .then(() => h(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n };\n if (typed) for (const h of typed) fire(h);\n for (const h of bus.wildcard) fire(h);\n\n if (cfg.onEvent) {\n Promise.resolve()\n .then(() => cfg.onEvent?.(withTimestamp))\n .catch(() => { /* observer errors do not propagate */ });\n }\n}\n","import type { HoleauthConfig, ProviderConfig } from '../types/index.js';\nimport { ProviderError } from '../errors/index.js';\nimport { buildAuthorizeUrl, generatePkcePair, generateState, generateNonce } from './client.js';\nimport { emit } from '../events/emitter.js';\n\nexport function findProvider(cfg: HoleauthConfig, id: string): ProviderConfig {\n const p = cfg.providers?.find((x) => x.id === id);\n if (!p) throw new ProviderError(`unknown provider: ${id}`);\n return p;\n}\n\n/**\n * Begin the SSO hop. Returns a URL to redirect the user to, plus state +\n * PKCE verifier the caller must persist (typically in httpOnly cookies)\n * to validate the callback.\n */\nexport async function authorize(\n cfg: HoleauthConfig,\n providerId: string,\n): Promise<{ url: string; state: string; codeVerifier: string; nonce?: string }> {\n const p = findProvider(cfg, providerId);\n const state = generateState();\n const { verifier, challenge } = await generatePkcePair();\n const nonce = p.kind === 'oidc' ? generateNonce() : undefined;\n\n const url = buildAuthorizeUrl({\n issuerAuthUrl: p.authorizationUrl,\n clientId: p.clientId,\n redirectUri: p.redirectUri,\n scopes: p.scopes,\n state,\n codeChallenge: challenge,\n nonce,\n });\n\n await emit(cfg, { type: 'sso.authorize', data: { provider: providerId } });\n return { url, state, codeVerifier: verifier, nonce };\n}\n","import { SignJWT, jwtVerify, decodeJwt, type JWTPayload } from 'jose';\nimport { InvalidTokenError } from '../errors/index.js';\n\nfunction toKey(secret: string | Uint8Array): Uint8Array {\n return typeof secret === 'string' ? new TextEncoder().encode(secret) : secret;\n}\n\nexport interface SignOptions {\n issuer?: string;\n audience?: string;\n subject?: string;\n expiresIn?: string | number; // e.g. '15m' or seconds\n jti?: string;\n}\n\nexport async function sign(\n payload: JWTPayload,\n secret: string | Uint8Array,\n opts: SignOptions = {},\n): Promise<string> {\n const jwt = new SignJWT(payload).setProtectedHeader({ alg: 'HS256' }).setIssuedAt();\n if (opts.issuer) jwt.setIssuer(opts.issuer);\n if (opts.audience) jwt.setAudience(opts.audience);\n if (opts.subject) jwt.setSubject(opts.subject);\n if (opts.jti) jwt.setJti(opts.jti);\n if (opts.expiresIn !== undefined) jwt.setExpirationTime(opts.expiresIn);\n return jwt.sign(toKey(secret));\n}\n\nexport async function verify<T extends JWTPayload = JWTPayload>(\n token: string,\n secret: string | Uint8Array,\n): Promise<T> {\n try {\n const { payload } = await jwtVerify(token, toKey(secret));\n return payload as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n\nexport function decode<T extends JWTPayload = JWTPayload>(token: string): T {\n try {\n return decodeJwt(token) as T;\n } catch (e) {\n throw new InvalidTokenError((e as Error).message);\n }\n}\n","/**\n * Double-submit CSRF protection.\n * The cookie holeauth.csrf is readable by JS (httpOnly:false). The client\n * echoes its value in header `x-csrf-token`; the server compares the two.\n * Because cross-origin JS cannot read the cookie, an attacker cannot mint\n * a matching header, defeating the cross-site POST scenario.\n */\n\nconst b64urlChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\nexport function generateCsrfToken(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n let out = '';\n for (const b of bytes) out += b64urlChars[b % 64];\n return out;\n}\n\n/** Constant-time compare. */\nexport function verifyCsrf(cookieValue: string | undefined, headerValue: string | undefined): boolean {\n if (!cookieValue || !headerValue) return false;\n if (cookieValue.length !== headerValue.length) return false;\n let diff = 0;\n for (let i = 0; i < cookieValue.length; i++) {\n diff |= cookieValue.charCodeAt(i) ^ headerValue.charCodeAt(i);\n }\n return diff === 0;\n}\n\nexport const CSRF_HEADER = 'x-csrf-token';\n","/**\n * Per-config hook runner attachment. Stored via WeakMap so the runner is\n * reachable from low-level helpers (session/issue, session/rotate, …)\n * without threading it through every signature.\n *\n * `defineHoleauth()` attaches the runner once at instance creation.\n */\nimport type { HoleauthConfig } from '../types/index.js';\nimport type { HookRunner } from './registry.js';\n\nconst runners = new WeakMap<HoleauthConfig, HookRunner>();\n\nexport function attachHookRunner(cfg: HoleauthConfig, runner: HookRunner): void {\n runners.set(cfg, runner);\n}\n\nconst NOOP: HookRunner = {\n async runRegisterBefore() {},\n async runRegisterAfter() {},\n async runSignInBefore() {},\n async runSignInChallenge() { return null; },\n async runSignInAfter() {},\n async runSignOutAfter() {},\n async runRefreshBefore() {},\n async runRefreshAfter() {},\n async runPasswordChangeBefore() {},\n async runPasswordChangeAfter() {},\n async runPasswordResetBefore() {},\n async runPasswordResetAfter() {},\n async runUserUpdateAfter() {},\n async runUserDeleteAfter() {},\n async runSessionIssue() {},\n async runSessionRotate() {},\n async runSessionRevoke() {},\n};\n\nexport function getHookRunner(cfg: HoleauthConfig): HookRunner {\n return runners.get(cfg) ?? NOOP;\n}\n","/** SHA-256 → base64url. Works on Node 20+ and all Edge runtimes. */\nexport async function sha256b64url(input: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));\n const bytes = new Uint8Array(buf);\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","import type { HoleauthConfig, IssuedTokens } from '../types/index.js';\nimport { sign } from '../jwt/index.js';\nimport { generateCsrfToken } from '../cookies/csrf.js';\nimport { emit } from '../events/emitter.js';\nimport { getHookRunner } from '../plugins/runner-ref.js';\nimport { sha256b64url } from './hash.js';\n\nconst ACCESS_DEFAULT = 900; // 15m\nconst REFRESH_DEFAULT = 2592000; // 30d\n\nexport interface IssueInput {\n userId: string;\n /** Omit to start a fresh family (e.g. on a real login). */\n familyId?: string;\n ip?: string | null;\n userAgent?: string | null;\n}\n\n/**\n * Mint a brand new session row + JWT pair + CSRF token.\n * Used by: fresh login, passkey login, SSO callback, 2FA verify.\n */\nexport async function issueSession(cfg: HoleauthConfig, input: IssueInput): Promise<IssuedTokens> {\n const accessTtl = cfg.tokens?.accessTtl ?? ACCESS_DEFAULT;\n const refreshTtl = cfg.tokens?.refreshTtl ?? REFRESH_DEFAULT;\n const now = Math.floor(Date.now() / 1000);\n\n const familyId = input.familyId ?? crypto.randomUUID();\n const sessionId = crypto.randomUUID();\n const nonce = crypto.randomUUID();\n\n const [accessToken, refreshToken] = await Promise.all([\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${accessTtl}s` },\n ),\n sign(\n { sid: sessionId, sub: input.userId, fam: familyId, typ: 'refresh', nce: nonce },\n cfg.secrets.jwtSecret,\n { expiresIn: `${refreshTtl}s`, jti: nonce },\n ),\n ]);\n const refreshTokenHash = await sha256b64url(refreshToken);\n\n await cfg.adapters.session.createSession({\n id: sessionId,\n userId: input.userId,\n familyId,\n refreshTokenHash,\n expiresAt: new Date((now + refreshTtl) * 1000),\n createdAt: new Date(),\n revokedAt: null,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n });\n\n const csrfToken = generateCsrfToken();\n\n await emit(cfg, {\n type: 'session.created',\n userId: input.userId,\n sessionId,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n data: { familyId },\n });\n await getHookRunner(cfg).runSessionIssue({ userId: input.userId, sessionId, familyId });\n\n return {\n accessToken,\n refreshToken,\n csrfToken,\n sessionId,\n familyId,\n accessExpiresAt: (now + accessTtl) * 1000,\n refreshExpiresAt: (now + refreshTtl) * 1000,\n };\n}\n","import type { HoleauthConfig, IssuedTokens, ProviderConfig } from '../types/index.js';\nimport type { AdapterUser } from '../adapters/index.js';\nimport { findProvider } from './authorize.js';\nimport { exchangeCode, fetchUserInfo } from './client.js';\nimport { decode } from '../jwt/index.js';\nimport { issueSession } from '../session/issue.js';\nimport { AccountConflictError, ProviderError } from '../errors/index.js';\nimport { emit } from '../events/emitter.js';\n\nexport interface CallbackInput {\n code: string;\n state: string;\n codeVerifier: string;\n ip?: string;\n userAgent?: string;\n}\n\ninterface NormalisedProfile {\n providerAccountId: string;\n email: string;\n name?: string | null;\n image?: string | null;\n emailVerified: boolean;\n}\n\nasync function exchangeAndProfile(\n p: ProviderConfig,\n input: CallbackInput,\n): Promise<{ tokens: Record<string, unknown>; profile: NormalisedProfile }> {\n const tokens = await exchangeCode({\n tokenUrl: p.tokenUrl,\n clientId: p.clientId,\n clientSecret: p.clientSecret,\n redirectUri: p.redirectUri,\n code: input.code,\n codeVerifier: input.codeVerifier,\n });\n\n const accessToken = typeof tokens.access_token === 'string' ? tokens.access_token : null;\n if (!accessToken) throw new ProviderError('no access_token in response');\n\n if (p.kind === 'oidc') {\n const idToken = typeof tokens.id_token === 'string' ? tokens.id_token : null;\n if (idToken) {\n const claims = decode<{\n sub?: string;\n email?: string;\n email_verified?: boolean;\n name?: string;\n picture?: string;\n }>(idToken);\n if (claims.sub && claims.email) {\n return {\n tokens,\n profile: {\n providerAccountId: claims.sub,\n email: claims.email.toLowerCase(),\n name: claims.name ?? null,\n image: claims.picture ?? null,\n emailVerified: claims.email_verified ?? false,\n },\n };\n }\n }\n // Fall back to userinfo\n const ui = await fetchUserInfo(p.userinfoUrl, accessToken);\n const sub = (ui.sub ?? '') as string;\n const email = typeof ui.email === 'string' ? ui.email.toLowerCase() : '';\n if (!sub || !email) throw new ProviderError('userinfo missing sub/email');\n return {\n tokens,\n profile: {\n providerAccountId: sub,\n email,\n name: (ui.name as string | null) ?? null,\n image: (ui.picture as string | null) ?? null,\n emailVerified: Boolean(ui.email_verified),\n },\n };\n }\n\n // oauth2\n const raw = await fetchUserInfo(p.userinfoUrl, accessToken);\n const mapped = p.profile(raw);\n if (!mapped.providerAccountId) throw new ProviderError('provider profile missing id');\n // GitHub may return null email — fall back to /user/emails.\n let email = mapped.email.toLowerCase();\n let verified = false;\n if (!email && p.id === 'github') {\n const emails = (await fetchUserInfo('https://api.github.com/user/emails', accessToken)) as unknown as Array<{\n email: string;\n primary: boolean;\n verified: boolean;\n }>;\n const primary = Array.isArray(emails) ? emails.find((e) => e.primary) : undefined;\n if (primary) {\n email = primary.email.toLowerCase();\n verified = primary.verified;\n }\n }\n if (!email) throw new ProviderError('provider did not return an email');\n return {\n tokens,\n profile: {\n providerAccountId: mapped.providerAccountId,\n email,\n name: mapped.name ?? null,\n image: mapped.image ?? null,\n emailVerified: verified,\n },\n };\n}\n\nasync function resolveUser(\n cfg: HoleauthConfig,\n provider: ProviderConfig,\n profile: NormalisedProfile,\n rawTokens: Record<string, unknown>,\n): Promise<AdapterUser> {\n const account = cfg.adapters.account;\n\n // 1. Try existing link\n if (account) {\n const existing = await account.getAccountByProvider(provider.id, profile.providerAccountId);\n if (existing) {\n const u = await cfg.adapters.user.getUserById(existing.userId);\n if (u) return u;\n }\n }\n\n // 2. Try user by email (potential linking)\n const byEmail = await cfg.adapters.user.getUserByEmail(profile.email);\n if (byEmail) {\n if (!cfg.allowDangerousEmailAccountLinking || !profile.emailVerified) {\n throw new AccountConflictError(\n `an account with email ${profile.email} already exists; enable allowDangerousEmailAccountLinking or sign in with password first`,\n );\n }\n // Auto-link\n if (account) {\n const linked = await account.linkAccount({\n userId: byEmail.id,\n provider: provider.id,\n providerAccountId: profile.providerAccountId,\n email: profile.email,\n accessToken: (rawTokens.access_token as string) ?? null,\n refreshToken: (rawTokens.refresh_token as string) ?? null,\n idToken: (rawTokens.id_token as string) ?? null,\n tokenType: (rawTokens.token_type as string) ?? null,\n scope: (rawTokens.scope as string) ?? null,\n expiresAt: typeof rawTokens.expires_in === 'number'\n ? new Date(Date.now() + (rawTokens.expires_in as number) * 1000)\n : null,\n });\n await emit(cfg, {\n type: 'account.linked',\n userId: byEmail.id,\n data: { provider: provider.id, accountId: linked.id, auto: true },\n });\n }\n return byEmail;\n }\n\n // 3. Create user + (maybe) link\n const user = await cfg.adapters.user.createUser({\n email: profile.email,\n name: profile.name ?? null,\n image: profile.image ?? null,\n emailVerified: profile.emailVerified ? new Date() : null,\n });\n if (account) {\n const linked = await account.linkAccount({\n userId: user.id,\n provider: provider.id,\n providerAccountId: profile.providerAccountId,\n email: profile.email,\n accessToken: (rawTokens.access_token as string) ?? null,\n refreshToken: (rawTokens.refresh_token as string) ?? null,\n idToken: (rawTokens.id_token as string) ?? null,\n tokenType: (rawTokens.token_type as string) ?? null,\n scope: (rawTokens.scope as string) ?? null,\n expiresAt: typeof rawTokens.expires_in === 'number'\n ? new Date(Date.now() + (rawTokens.expires_in as number) * 1000)\n : null,\n });\n await emit(cfg, {\n type: 'account.linked',\n userId: user.id,\n data: { provider: provider.id, accountId: linked.id, onCreate: true },\n });\n }\n return user;\n}\n\nexport async function callback(\n cfg: HoleauthConfig,\n providerId: string,\n input: CallbackInput,\n): Promise<{ user: AdapterUser; tokens: IssuedTokens }> {\n const p = findProvider(cfg, providerId);\n try {\n const { tokens: rawTokens, profile } = await exchangeAndProfile(p, input);\n const user = await resolveUser(cfg, p, profile, rawTokens);\n\n const tokens = await issueSession(cfg, {\n userId: user.id,\n ip: input.ip ?? null,\n userAgent: input.userAgent ?? null,\n });\n await emit(cfg, {\n type: 'sso.callback_ok',\n userId: user.id,\n sessionId: tokens.sessionId,\n data: { provider: providerId },\n });\n return { user, tokens };\n } catch (e) {\n await emit(cfg, {\n type: 'sso.callback_failed',\n data: { provider: providerId, error: (e as Error).message },\n });\n throw e;\n }\n}\n","import type { OIDCProviderConfig } from '../../types/index.js';\n\nexport interface GoogleOptions {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n id?: string;\n scopes?: string[];\n}\n\n/** Google OpenID Connect provider. */\nexport function GoogleProvider(opts: GoogleOptions): OIDCProviderConfig {\n return {\n kind: 'oidc',\n id: opts.id ?? 'google',\n name: 'Google',\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['openid', 'email', 'profile'],\n issuer: 'https://accounts.google.com',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n userinfoUrl: 'https://openidconnect.googleapis.com/v1/userinfo',\n };\n}\n","import type { OAuth2ProviderConfig } from '../../types/index.js';\n\nexport interface GithubOptions {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n id?: string;\n scopes?: string[];\n}\n\n/** GitHub OAuth2 provider. Uses REST userinfo (no OIDC). */\nexport function GithubProvider(opts: GithubOptions): OAuth2ProviderConfig {\n return {\n kind: 'oauth2',\n id: opts.id ?? 'github',\n name: 'GitHub',\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['read:user', 'user:email'],\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n userinfoUrl: 'https://api.github.com/user',\n profile: (raw) => {\n const p = (raw ?? {}) as {\n id?: number | string;\n login?: string;\n email?: string | null;\n name?: string | null;\n avatar_url?: string | null;\n };\n return {\n providerAccountId: String(p.id ?? p.login ?? ''),\n email: p.email ?? '',\n name: p.name ?? p.login ?? null,\n image: p.avatar_url ?? null,\n };\n },\n };\n}\n","import type { OAuth2ProviderConfig } from '../../types/index.js';\n\nexport interface DiscordOptions {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n id?: string;\n scopes?: string[];\n}\n\n/** Discord OAuth2 provider. Uses REST userinfo (no OIDC discovery). */\nexport function DiscordProvider(opts: DiscordOptions): OAuth2ProviderConfig {\n return {\n kind: 'oauth2',\n id: opts.id ?? 'discord',\n name: 'Discord',\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['identify', 'email'],\n authorizationUrl: 'https://discord.com/oauth2/authorize',\n tokenUrl: 'https://discord.com/api/oauth2/token',\n userinfoUrl: 'https://discord.com/api/users/@me',\n profile: (raw) => {\n const p = (raw ?? {}) as {\n id?: string;\n username?: string;\n global_name?: string | null;\n email?: string | null;\n avatar?: string | null;\n };\n const id = String(p.id ?? '');\n const image =\n id && p.avatar ? `https://cdn.discordapp.com/avatars/${id}/${p.avatar}.png` : null;\n return {\n providerAccountId: id,\n email: p.email ?? '',\n name: p.global_name ?? p.username ?? null,\n image,\n };\n },\n };\n}\n","import type { OIDCProviderConfig } from '../../types/index.js';\n\nexport interface MicrosoftOptions {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n /**\n * Microsoft tenant. Common values:\n * - 'common' → both work + school and personal accounts\n * - 'organizations' → work + school only\n * - 'consumers' → personal Microsoft accounts only\n * - '<tenant-guid>' → a specific Azure AD tenant\n *\n * Default: 'common'.\n */\n tenantId?: string;\n id?: string;\n scopes?: string[];\n}\n\n/**\n * Microsoft Identity Platform (Azure AD / Entra ID) OpenID Connect provider.\n *\n * Note: the issuer for tenant 'common' is technically per-tenant at runtime\n * (`https://login.microsoftonline.com/{tid}/v2.0`). We expose the multi-tenant\n * issuer string; callers that need strict issuer validation should pin a\n * specific tenant ID.\n */\nexport function MicrosoftProvider(opts: MicrosoftOptions): OIDCProviderConfig {\n const tenant = opts.tenantId ?? 'common';\n const base = `https://login.microsoftonline.com/${tenant}`;\n return {\n kind: 'oidc',\n id: opts.id ?? 'microsoft',\n name: 'Microsoft',\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['openid', 'email', 'profile'],\n issuer: `${base}/v2.0`,\n authorizationUrl: `${base}/oauth2/v2.0/authorize`,\n tokenUrl: `${base}/oauth2/v2.0/token`,\n userinfoUrl: 'https://graph.microsoft.com/oidc/userinfo',\n };\n}\n","import type { OIDCProviderConfig } from '../../types/index.js';\n\nexport interface OIDCOptions {\n /** Provider id (used as the `:provider` URL segment). */\n id: string;\n /** Display name. */\n name?: string;\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n /** OIDC issuer (used for ID token `iss` validation). */\n issuer: string;\n authorizationUrl: string;\n tokenUrl: string;\n userinfoUrl: string;\n scopes?: string[];\n}\n\n/**\n * Generic OpenID Connect provider. Use this for any spec-compliant OIDC\n * Identity Provider (Keycloak, Auth0, Okta, Authentik, holeauth-as-IDP, …).\n *\n * Endpoint discovery is currently the caller's responsibility — fetch\n * `${issuer}/.well-known/openid-configuration` and pass the resulting URLs.\n */\nexport function OIDCProvider(opts: OIDCOptions): OIDCProviderConfig {\n return {\n kind: 'oidc',\n id: opts.id,\n name: opts.name ?? opts.id,\n clientId: opts.clientId,\n clientSecret: opts.clientSecret,\n redirectUri: opts.redirectUri,\n scopes: opts.scopes ?? ['openid', 'email', 'profile'],\n issuer: opts.issuer,\n authorizationUrl: opts.authorizationUrl,\n tokenUrl: opts.tokenUrl,\n userinfoUrl: opts.userinfoUrl,\n };\n}\n"]}