@kamod-ch/otok-auth 1.0.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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/dist/adapters/index.d.ts +2 -0
  4. package/dist/adapters/index.d.ts.map +1 -0
  5. package/dist/adapters/index.js +2 -0
  6. package/dist/adapters/index.js.map +1 -0
  7. package/dist/adapters/kysely.d.ts +12 -0
  8. package/dist/adapters/kysely.d.ts.map +1 -0
  9. package/dist/adapters/kysely.js +44 -0
  10. package/dist/adapters/kysely.js.map +1 -0
  11. package/dist/adapters/memory.d.ts +26 -0
  12. package/dist/adapters/memory.d.ts.map +1 -0
  13. package/dist/adapters/memory.js +70 -0
  14. package/dist/adapters/memory.js.map +1 -0
  15. package/dist/context.d.ts +36 -0
  16. package/dist/context.d.ts.map +1 -0
  17. package/dist/context.js +68 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/crypto.d.ts +5 -0
  20. package/dist/crypto.d.ts.map +1 -0
  21. package/dist/crypto.js +33 -0
  22. package/dist/crypto.js.map +1 -0
  23. package/dist/csrf.d.ts +19 -0
  24. package/dist/csrf.d.ts.map +1 -0
  25. package/dist/csrf.js +53 -0
  26. package/dist/csrf.js.map +1 -0
  27. package/dist/errors.d.ts +13 -0
  28. package/dist/errors.d.ts.map +1 -0
  29. package/dist/errors.js +29 -0
  30. package/dist/errors.js.map +1 -0
  31. package/dist/index.d.ts +16 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +15 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/loader.d.ts +24 -0
  36. package/dist/loader.d.ts.map +1 -0
  37. package/dist/loader.js +30 -0
  38. package/dist/loader.js.map +1 -0
  39. package/dist/middleware/api-guard.d.ts +3 -0
  40. package/dist/middleware/api-guard.d.ts.map +1 -0
  41. package/dist/middleware/api-guard.js +4 -0
  42. package/dist/middleware/api-guard.js.map +1 -0
  43. package/dist/middleware/csrf.d.ts +4 -0
  44. package/dist/middleware/csrf.d.ts.map +1 -0
  45. package/dist/middleware/csrf.js +21 -0
  46. package/dist/middleware/csrf.js.map +1 -0
  47. package/dist/middleware/index.d.ts +5 -0
  48. package/dist/middleware/index.d.ts.map +1 -0
  49. package/dist/middleware/index.js +5 -0
  50. package/dist/middleware/index.js.map +1 -0
  51. package/dist/middleware/rbac.d.ts +26 -0
  52. package/dist/middleware/rbac.d.ts.map +1 -0
  53. package/dist/middleware/rbac.js +63 -0
  54. package/dist/middleware/rbac.js.map +1 -0
  55. package/dist/middleware/require-auth.d.ts +11 -0
  56. package/dist/middleware/require-auth.d.ts.map +1 -0
  57. package/dist/middleware/require-auth.js +20 -0
  58. package/dist/middleware/require-auth.js.map +1 -0
  59. package/dist/password-webcrypto.d.ts +11 -0
  60. package/dist/password-webcrypto.d.ts.map +1 -0
  61. package/dist/password-webcrypto.js +67 -0
  62. package/dist/password-webcrypto.js.map +1 -0
  63. package/dist/password.d.ts +3 -0
  64. package/dist/password.d.ts.map +1 -0
  65. package/dist/password.js +8 -0
  66. package/dist/password.js.map +1 -0
  67. package/dist/plugin.d.ts +19 -0
  68. package/dist/plugin.d.ts.map +1 -0
  69. package/dist/plugin.js +132 -0
  70. package/dist/plugin.js.map +1 -0
  71. package/dist/redirect.d.ts +8 -0
  72. package/dist/redirect.d.ts.map +1 -0
  73. package/dist/redirect.js +21 -0
  74. package/dist/redirect.js.map +1 -0
  75. package/dist/registry.d.ts +22 -0
  76. package/dist/registry.d.ts.map +1 -0
  77. package/dist/registry.js +28 -0
  78. package/dist/registry.js.map +1 -0
  79. package/dist/session/index.d.ts +3 -0
  80. package/dist/session/index.d.ts.map +1 -0
  81. package/dist/session/index.js +2 -0
  82. package/dist/session/index.js.map +1 -0
  83. package/dist/session/manager.d.ts +3 -0
  84. package/dist/session/manager.d.ts.map +1 -0
  85. package/dist/session/manager.js +120 -0
  86. package/dist/session/manager.js.map +1 -0
  87. package/dist/session/types.d.ts +41 -0
  88. package/dist/session/types.d.ts.map +1 -0
  89. package/dist/session/types.js +2 -0
  90. package/dist/session/types.js.map +1 -0
  91. package/dist/types.d.ts +43 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/types.js +2 -0
  94. package/dist/types.js.map +1 -0
  95. package/package.json +110 -0
package/dist/plugin.js ADDED
@@ -0,0 +1,132 @@
1
+ import { definePlugin } from "@kamod-ch/otok";
2
+ import { createAuthHelpers } from "./context.js";
3
+ import { createCsrfMiddleware } from "./middleware/csrf.js";
4
+ import { createRequireAuthMiddleware } from "./middleware/require-auth.js";
5
+ import { registerAuthRuntime } from "./registry.js";
6
+ import { createSessionManager } from "./session/manager.js";
7
+ function resolveSessionCookie(options) {
8
+ return options.cookieName ?? options.sessionCookie ?? "otok_session";
9
+ }
10
+ function resolveSecret(options) {
11
+ const secret = options.secret ?? process.env.AUTH_SECRET;
12
+ if (!secret || secret.length < 32) {
13
+ throw new Error("otok-auth: provide secret (min 32 bytes) or set AUTH_SECRET");
14
+ }
15
+ return secret;
16
+ }
17
+ function configureAuthApp(app, options) {
18
+ resolveSecret(options);
19
+ const sessionCookie = resolveSessionCookie(options.session);
20
+ const csrfCookie = options.session.csrfCookie ?? "otok_csrf";
21
+ const contextKey = options.contextKey ?? "user";
22
+ const loginPath = options.loginPath ?? "/login";
23
+ const logoutPath = options.logoutPath ?? "/auth/logout";
24
+ const redirectAllowlist = options.redirectAllowlist ?? ["/"];
25
+ const sessions = createSessionManager({
26
+ sessionCookie,
27
+ csrfCookie,
28
+ maxAgeSeconds: options.session.maxAgeSeconds,
29
+ secure: options.session.secure,
30
+ sameSite: options.session.sameSite,
31
+ path: options.session.path,
32
+ rotationIntervalSeconds: options.session.rotationIntervalSeconds,
33
+ }, options.adapter);
34
+ const helpers = createAuthHelpers({
35
+ sessions,
36
+ contextKey,
37
+ loginPath,
38
+ redirectAllowlist,
39
+ getRole: options.getRole,
40
+ });
41
+ registerAuthRuntime({
42
+ sessions,
43
+ helpers,
44
+ contextKey,
45
+ loginPath,
46
+ logoutPath,
47
+ redirectAllowlist,
48
+ });
49
+ app.post(logoutPath, async (c) => {
50
+ await sessions.revokeSession(c);
51
+ return c.redirect(loginPath, 303);
52
+ });
53
+ app.use("*", async (c, next) => {
54
+ const user = await sessions.getSessionUser(c);
55
+ if (user)
56
+ c.set(contextKey, user);
57
+ await next();
58
+ });
59
+ }
60
+ const authPluginFactory = definePlugin({
61
+ name: "@kamod-ch/otok-auth",
62
+ version: "1.1.0",
63
+ schema: {
64
+ parse(input) {
65
+ if (!input || typeof input !== "object") {
66
+ throw new Error("auth() options must be an object");
67
+ }
68
+ const record = input;
69
+ if (!record.session || typeof record.session !== "object") {
70
+ throw new Error("auth() requires session options");
71
+ }
72
+ if (!record.adapter || typeof record.adapter !== "object") {
73
+ throw new Error("auth() requires a SessionAdapter");
74
+ }
75
+ return input;
76
+ },
77
+ },
78
+ envSchema: {
79
+ parse(input) {
80
+ return {
81
+ authSecret: input.AUTH_SECRET,
82
+ };
83
+ },
84
+ },
85
+ });
86
+ /** Otok plugin factory — register after `auth()` in otok.config.ts. */
87
+ export default function auth(options) {
88
+ const plugin = authPluginFactory(options);
89
+ plugin.configureApp = ({ app }) => {
90
+ configureAuthApp(app, options);
91
+ };
92
+ return plugin;
93
+ }
94
+ /** Factory for programmatic (non-plugin) setup — same options as the plugin. */
95
+ export function createAuthRuntime(options) {
96
+ resolveSecret(options);
97
+ const sessionCookie = resolveSessionCookie(options.session);
98
+ const csrfCookie = options.session.csrfCookie ?? "otok_csrf";
99
+ const contextKey = options.contextKey ?? "user";
100
+ const loginPath = options.loginPath ?? "/login";
101
+ const redirectAllowlist = options.redirectAllowlist ?? ["/"];
102
+ const sessions = createSessionManager({
103
+ sessionCookie,
104
+ csrfCookie,
105
+ maxAgeSeconds: options.session.maxAgeSeconds,
106
+ secure: options.session.secure,
107
+ sameSite: options.session.sameSite,
108
+ path: options.session.path,
109
+ rotationIntervalSeconds: options.session.rotationIntervalSeconds,
110
+ }, options.adapter);
111
+ const helpers = createAuthHelpers({
112
+ sessions,
113
+ contextKey,
114
+ loginPath,
115
+ redirectAllowlist,
116
+ getRole: options.getRole,
117
+ });
118
+ return {
119
+ ...helpers,
120
+ sessions,
121
+ middleware: {
122
+ requireAuth: createRequireAuthMiddleware({
123
+ getUser: (c) => sessions.getSessionUser(c),
124
+ loginPath,
125
+ contextKey,
126
+ }),
127
+ csrf: createCsrfMiddleware({ cookieName: csrfCookie }),
128
+ },
129
+ };
130
+ }
131
+ export { configureAuthApp };
132
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Validates a post-login redirect target against an allowlist.
3
+ * Only same-origin relative paths are accepted; `//` and external URLs are rejected.
4
+ */
5
+ export declare function safeRedirectPath(raw: string | null | undefined, allowlist?: readonly string[]): string | null;
6
+ /** @deprecated Use `safeRedirectPath`. Kept for backward compatibility. */
7
+ export declare const safeNextPath: typeof safeRedirectPath;
8
+ //# sourceMappingURL=redirect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.d.ts","sourceRoot":"","sources":["../src/redirect.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,SAAS,GAAE,SAAS,MAAM,EAAsB,GAC/C,MAAM,GAAG,IAAI,CAWf;AAED,2EAA2E;AAC3E,eAAO,MAAM,YAAY,yBAAmB,CAAC"}
@@ -0,0 +1,21 @@
1
+ const DEFAULT_ALLOWLIST = ["/"];
2
+ /**
3
+ * Validates a post-login redirect target against an allowlist.
4
+ * Only same-origin relative paths are accepted; `//` and external URLs are rejected.
5
+ */
6
+ export function safeRedirectPath(raw, allowlist = DEFAULT_ALLOWLIST) {
7
+ if (!raw)
8
+ return null;
9
+ if (!raw.startsWith("/") || raw.startsWith("//"))
10
+ return null;
11
+ const allowed = allowlist.length > 0 ? allowlist : DEFAULT_ALLOWLIST;
12
+ const matches = allowed.some((prefix) => {
13
+ if (prefix === "/")
14
+ return true;
15
+ return raw === prefix || raw.startsWith(`${prefix}/`);
16
+ });
17
+ return matches ? raw : null;
18
+ }
19
+ /** @deprecated Use `safeRedirectPath`. Kept for backward compatibility. */
20
+ export const safeNextPath = safeRedirectPath;
21
+ //# sourceMappingURL=redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.js","sourceRoot":"","sources":["../src/redirect.ts"],"names":[],"mappings":"AAAA,MAAM,iBAAiB,GAAG,CAAC,GAAG,CAAU,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAA8B,EAC9B,YAA+B,iBAAiB;IAEhD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9D,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACtC,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,OAAO,GAAG,KAAK,MAAM,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Context } from "hono";
2
+ import type { AuthHelpers } from "./context.js";
3
+ import type { SessionManager } from "./session/types.js";
4
+ import type { AuthUser } from "./types.js";
5
+ export interface AuthRuntime<TUser extends AuthUser = AuthUser> {
6
+ sessions: SessionManager<TUser>;
7
+ helpers: AuthHelpers<TUser>;
8
+ contextKey: string;
9
+ loginPath: string;
10
+ logoutPath: string;
11
+ redirectAllowlist: readonly string[];
12
+ }
13
+ /** @internal Test helper */
14
+ export declare function resetAuthRuntimeForTests(): void;
15
+ export declare function registerAuthRuntime<TUser extends AuthUser>(value: AuthRuntime<TUser>): void;
16
+ export declare function getAuthRuntime<TUser extends AuthUser = AuthUser>(): AuthRuntime<TUser>;
17
+ export declare function tryGetAuthRuntime<TUser extends AuthUser = AuthUser>(): AuthRuntime<TUser> | null;
18
+ /** Convenience for API routes outside the plugin registry. */
19
+ export declare function getSession<TUser extends AuthUser = AuthUser>(c: Context): Promise<TUser | null>;
20
+ export declare function requireUser<TUser extends AuthUser = AuthUser>(c: Context): Promise<TUser>;
21
+ export declare function requireRole<TUser extends AuthUser = AuthUser>(c: Context, role: string): Promise<TUser>;
22
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAC5D,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAID,4BAA4B;AAC5B,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,IAAI,CAE3F;AAED,wBAAgB,cAAc,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,KAAK,WAAW,CAAC,KAAK,CAAC,CAOtF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,KAAK,WAAW,CAAC,KAAK,CAAC,GAAG,IAAI,CAEhG;AAED,8DAA8D;AAC9D,wBAAsB,UAAU,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAErG;AAED,wBAAsB,WAAW,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAE/F;AAED,wBAAsB,WAAW,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAE7G"}
@@ -0,0 +1,28 @@
1
+ let runtime = null;
2
+ /** @internal Test helper */
3
+ export function resetAuthRuntimeForTests() {
4
+ runtime = null;
5
+ }
6
+ export function registerAuthRuntime(value) {
7
+ runtime = value;
8
+ }
9
+ export function getAuthRuntime() {
10
+ if (!runtime) {
11
+ throw new Error("otok-auth: no auth runtime registered. Add auth() to otok.config.ts plugins or call registerAuthRuntime().");
12
+ }
13
+ return runtime;
14
+ }
15
+ export function tryGetAuthRuntime() {
16
+ return runtime;
17
+ }
18
+ /** Convenience for API routes outside the plugin registry. */
19
+ export async function getSession(c) {
20
+ return getAuthRuntime().helpers.getSession(c);
21
+ }
22
+ export async function requireUser(c) {
23
+ return getAuthRuntime().helpers.requireUser(c);
24
+ }
25
+ export async function requireRole(c, role) {
26
+ return getAuthRuntime().helpers.requireRole(c, role);
27
+ }
28
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAcA,IAAI,OAAO,GAAuB,IAAI,CAAC;AAEvC,4BAA4B;AAC5B,MAAM,UAAU,wBAAwB;IACtC,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAyB,KAAyB;IACnF,OAAO,GAAG,KAAoB,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,4GAA4G,CAC7G,CAAC;IACJ,CAAC;IACD,OAAO,OAA6B,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,OAAoC,CAAC;AAC9C,CAAC;AAED,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,UAAU,CAAoC,CAAU;IAC5E,OAAO,cAAc,EAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAoC,CAAU;IAC7E,OAAO,cAAc,EAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAoC,CAAU,EAAE,IAAY;IAC3F,OAAO,cAAc,EAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { createSessionManager } from "./manager.js";
2
+ export type { CreateSessionRecordInput, ResolvedSessionRecord, SessionAdapter, SessionConfig, SessionManager, } from "./types.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EACV,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createSessionManager } from "./manager.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SessionAdapter, SessionConfig, SessionManager } from "./types.js";
2
+ export declare function createSessionManager<TUser>(config: SessionConfig, adapter: SessionAdapter<TUser>): SessionManager<TUser>;
3
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAchF,wBAAgB,oBAAoB,CAAC,KAAK,EACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,GAC7B,cAAc,CAAC,KAAK,CAAC,CA6GvB"}
@@ -0,0 +1,120 @@
1
+ import { deleteCookie, getCookie, setCookie } from "hono/cookie";
2
+ import { randomToken, sha256 } from "../crypto.js";
3
+ const DEFAULT_MAX_AGE = 60 * 60 * 24 * 14;
4
+ function resolveSecure(c, secure) {
5
+ if (typeof secure === "function")
6
+ return secure(c);
7
+ if (typeof secure === "boolean")
8
+ return secure;
9
+ return process.env.NODE_ENV === "production";
10
+ }
11
+ function defaultRotationInterval(maxAgeSeconds) {
12
+ return Math.floor(maxAgeSeconds / 2);
13
+ }
14
+ export function createSessionManager(config, adapter) {
15
+ const maxAgeSeconds = config.maxAgeSeconds ?? DEFAULT_MAX_AGE;
16
+ const path = config.path ?? "/";
17
+ const sameSite = config.sameSite ?? "Lax";
18
+ const rotationIntervalSeconds = config.rotationIntervalSeconds ?? defaultRotationInterval(maxAgeSeconds);
19
+ const resolvedConfig = {
20
+ ...config,
21
+ sessionCookie: config.sessionCookie,
22
+ maxAgeSeconds,
23
+ rotationIntervalSeconds,
24
+ };
25
+ function setSessionCookies(c, token) {
26
+ const secure = resolveSecure(c, config.secure);
27
+ setCookie(c, config.sessionCookie, token, {
28
+ httpOnly: true,
29
+ secure,
30
+ sameSite,
31
+ path,
32
+ maxAge: maxAgeSeconds,
33
+ });
34
+ if (config.csrfCookie) {
35
+ setCookie(c, config.csrfCookie, randomToken(), {
36
+ httpOnly: false,
37
+ secure,
38
+ sameSite,
39
+ path,
40
+ maxAge: maxAgeSeconds,
41
+ });
42
+ }
43
+ }
44
+ async function createSession(c, userId) {
45
+ const token = randomToken();
46
+ const tokenHash = sha256(token);
47
+ const expiresAt = new Date(Date.now() + maxAgeSeconds * 1000);
48
+ await adapter.createRecord({
49
+ tokenHash,
50
+ userId,
51
+ expiresAt,
52
+ userAgent: c.req.header("user-agent") ?? null,
53
+ ipAddress: null,
54
+ });
55
+ setSessionCookies(c, token);
56
+ }
57
+ async function revokeSession(c) {
58
+ const token = getCookie(c, config.sessionCookie);
59
+ if (token)
60
+ await adapter.revokeRecord(sha256(token));
61
+ deleteCookie(c, config.sessionCookie, { path });
62
+ if (config.csrfCookie)
63
+ deleteCookie(c, config.csrfCookie, { path });
64
+ }
65
+ async function rotateSession(c) {
66
+ const token = getCookie(c, config.sessionCookie);
67
+ if (!token)
68
+ return;
69
+ const tokenHash = sha256(token);
70
+ const record = adapter.resolveRecord ? await adapter.resolveRecord(tokenHash) : null;
71
+ if (!record) {
72
+ await revokeSession(c);
73
+ return;
74
+ }
75
+ await adapter.revokeRecord(tokenHash);
76
+ const newToken = randomToken();
77
+ const newHash = sha256(newToken);
78
+ await adapter.createRecord({
79
+ tokenHash: newHash,
80
+ userId: record.userId,
81
+ expiresAt: record.expiresAt,
82
+ userAgent: c.req.header("user-agent") ?? null,
83
+ ipAddress: null,
84
+ });
85
+ setSessionCookies(c, newToken);
86
+ }
87
+ async function getSessionUser(c) {
88
+ const token = getCookie(c, config.sessionCookie);
89
+ if (!token)
90
+ return null;
91
+ const tokenHash = sha256(token);
92
+ const user = await adapter.resolveUser(tokenHash);
93
+ if (!user)
94
+ return null;
95
+ if (adapter.resolveRecord) {
96
+ const record = await adapter.resolveRecord(tokenHash);
97
+ if (record) {
98
+ const ageSeconds = (Date.now() - record.createdAt.getTime()) / 1000;
99
+ if (ageSeconds >= rotationIntervalSeconds) {
100
+ await rotateSession(c);
101
+ }
102
+ else {
103
+ await adapter.touchRecord?.(tokenHash);
104
+ }
105
+ }
106
+ }
107
+ else {
108
+ await adapter.touchRecord?.(tokenHash);
109
+ }
110
+ return user;
111
+ }
112
+ return {
113
+ createSession,
114
+ revokeSession,
115
+ rotateSession,
116
+ getSessionUser,
117
+ config: resolvedConfig,
118
+ };
119
+ }
120
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { Context } from "hono";
2
+ export interface SessionConfig {
3
+ sessionCookie: string;
4
+ csrfCookie?: string;
5
+ maxAgeSeconds?: number;
6
+ secure?: boolean | ((c: Context) => boolean);
7
+ sameSite?: "Strict" | "Lax" | "None";
8
+ path?: string;
9
+ /** Rotate session token after this interval (seconds). Defaults to half of maxAgeSeconds. */
10
+ rotationIntervalSeconds?: number;
11
+ }
12
+ export interface CreateSessionRecordInput {
13
+ tokenHash: string;
14
+ userId: string;
15
+ expiresAt: Date;
16
+ userAgent: string | null;
17
+ ipAddress: string | null;
18
+ }
19
+ export interface ResolvedSessionRecord {
20
+ tokenHash: string;
21
+ userId: string;
22
+ createdAt: Date;
23
+ expiresAt: Date;
24
+ }
25
+ export interface SessionAdapter<TUser> {
26
+ createRecord(input: CreateSessionRecordInput): Promise<void>;
27
+ revokeRecord(tokenHash: string): Promise<void>;
28
+ resolveUser(tokenHash: string): Promise<TUser | null>;
29
+ touchRecord?(tokenHash: string): Promise<void>;
30
+ /** Return session metadata for rotation decisions. */
31
+ resolveRecord?(tokenHash: string): Promise<ResolvedSessionRecord | null>;
32
+ }
33
+ export interface SessionManager<TUser> {
34
+ createSession(c: Context, userId: string): Promise<void>;
35
+ revokeSession(c: Context): Promise<void>;
36
+ /** Re-issue session cookie with a new token for the same user (rotation). */
37
+ rotateSession(c: Context): Promise<void>;
38
+ getSessionUser(c: Context): Promise<TUser | null>;
39
+ readonly config: Required<Pick<SessionConfig, "sessionCookie" | "maxAgeSeconds">> & SessionConfig;
40
+ }
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/session/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6FAA6F;IAC7F,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,cAAc,CAAC,KAAK;IACnC,YAAY,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACtD,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,sDAAsD;IACtD,aAAa,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,cAAc,CAAC,KAAK;IACnC,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,6EAA6E;IAC7E,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAClD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,eAAe,GAAG,eAAe,CAAC,CAAC,GAAG,aAAa,CAAC;CACnG"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/session/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import type { Context } from "hono";
2
+ import type { SessionAdapter } from "./session/types.js";
3
+ /** Default user shape — extend in your app via generics. */
4
+ export interface AuthUser {
5
+ id: string;
6
+ email?: string | null;
7
+ name?: string | null;
8
+ role?: string;
9
+ [key: string]: unknown;
10
+ }
11
+ export interface AuthSession<TUser extends AuthUser = AuthUser> {
12
+ user: TUser;
13
+ userId: string;
14
+ issuedAt: Date;
15
+ expiresAt: Date;
16
+ }
17
+ export interface AuthPluginSessionOptions {
18
+ /** Session cookie name. Alias: `cookieName`. */
19
+ cookieName?: string;
20
+ sessionCookie?: string;
21
+ csrfCookie?: string;
22
+ maxAgeSeconds?: number;
23
+ secure?: boolean | ((c: Context) => boolean);
24
+ sameSite?: "Strict" | "Lax" | "None";
25
+ path?: string;
26
+ /** Rotate session token after this many seconds (default: half of maxAge). */
27
+ rotationIntervalSeconds?: number;
28
+ }
29
+ export interface AuthPluginOptions<TUser extends AuthUser = AuthUser> {
30
+ session: AuthPluginSessionOptions;
31
+ /** Required for plugin mode — app-owned persistence. */
32
+ adapter: SessionAdapter<TUser>;
33
+ /** HMAC secret for signed payloads (min 32 bytes). Falls back to env AUTH_SECRET. */
34
+ secret?: string;
35
+ contextKey?: string;
36
+ loginPath?: string;
37
+ logoutPath?: string;
38
+ /** Allowed post-login redirect path prefixes (open-redirect safe). */
39
+ redirectAllowlist?: readonly string[];
40
+ /** Role accessor for RBAC helpers. */
41
+ getRole?: (user: TUser) => string;
42
+ }
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,4DAA4D;AAC5D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAC5D,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAClE,OAAO,EAAE,wBAAwB,CAAC;IAClC,wDAAwD;IACxD,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/B,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,sCAAsC;IACtC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC;CACnC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,110 @@
1
+ {
2
+ "name": "@kamod-ch/otok-auth",
3
+ "version": "1.0.0",
4
+ "description": "Cookie sessions, CSRF, and route middleware helpers for Otok apps.",
5
+ "homepage": "https://github.com/kamod-ch/otok/tree/main/packages/otok-auth#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/kamod-ch/otok/issues"
8
+ },
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/kamod-ch/otok.git",
13
+ "directory": "packages/otok-auth"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "type": "module",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "./session": {
26
+ "types": "./dist/session/index.d.ts",
27
+ "default": "./dist/session/index.js"
28
+ },
29
+ "./middleware": {
30
+ "types": "./dist/middleware/index.d.ts",
31
+ "default": "./dist/middleware/index.js"
32
+ },
33
+ "./csrf": {
34
+ "types": "./dist/csrf.d.ts",
35
+ "default": "./dist/csrf.js"
36
+ },
37
+ "./password": {
38
+ "types": "./dist/password.d.ts",
39
+ "default": "./dist/password.js"
40
+ },
41
+ "./password/webcrypto": {
42
+ "types": "./dist/password-webcrypto.d.ts",
43
+ "default": "./dist/password-webcrypto.js"
44
+ },
45
+ "./adapters/memory": {
46
+ "types": "./dist/adapters/index.d.ts",
47
+ "default": "./dist/adapters/index.js"
48
+ },
49
+ "./adapters/kysely": {
50
+ "types": "./dist/adapters/kysely.d.ts",
51
+ "default": "./dist/adapters/kysely.js"
52
+ },
53
+ "./plugin": {
54
+ "types": "./dist/plugin.d.ts",
55
+ "default": "./dist/plugin.js"
56
+ },
57
+ "./context": {
58
+ "types": "./dist/context.d.ts",
59
+ "default": "./dist/context.js"
60
+ },
61
+ "./registry": {
62
+ "types": "./dist/registry.d.ts",
63
+ "default": "./dist/registry.js"
64
+ },
65
+ "./loader": {
66
+ "types": "./dist/loader.d.ts",
67
+ "default": "./dist/loader.js"
68
+ },
69
+ "./redirect": {
70
+ "types": "./dist/redirect.d.ts",
71
+ "default": "./dist/redirect.js"
72
+ }
73
+ },
74
+ "publishConfig": {
75
+ "access": "public"
76
+ },
77
+ "devDependencies": {
78
+ "@kamod-ch/otok": "1.0.0",
79
+ "@kamod-ch/otok-test": "1.0.0",
80
+ "@node-rs/argon2": "^2.0.2",
81
+ "@types/node": "^24.12.2",
82
+ "hono": "^4.13.8",
83
+ "kysely": "^0.29.2",
84
+ "preact": "^10.28.2",
85
+ "typescript": "~6.0.2",
86
+ "vitest": "^4.1.2"
87
+ },
88
+ "peerDependencies": {
89
+ "@kamod-ch/otok": ">=0.6.1",
90
+ "@node-rs/argon2": ">=2.0.0",
91
+ "hono": ">=4",
92
+ "kysely": ">=0.27.0"
93
+ },
94
+ "peerDependenciesMeta": {
95
+ "@node-rs/argon2": {
96
+ "optional": true
97
+ },
98
+ "kysely": {
99
+ "optional": true
100
+ }
101
+ },
102
+ "engines": {
103
+ "node": ">=20"
104
+ },
105
+ "scripts": {
106
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
107
+ "typecheck": "tsc -p tsconfig.json --noEmit",
108
+ "test": "vitest run"
109
+ }
110
+ }