@soulcraft/sdk 2.6.1 → 3.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.
- package/dist/modules/auth/backchannel.d.ts +13 -39
- package/dist/modules/auth/backchannel.d.ts.map +1 -1
- package/dist/modules/auth/backchannel.js +12 -144
- package/dist/modules/auth/backchannel.js.map +1 -1
- package/dist/modules/auth/middleware.d.ts +45 -157
- package/dist/modules/auth/middleware.d.ts.map +1 -1
- package/dist/modules/auth/middleware.js +40 -322
- package/dist/modules/auth/middleware.js.map +1 -1
- package/dist/modules/auth/products.d.ts +1 -1
- package/dist/modules/auth/products.js +1 -1
- package/dist/modules/auth/request-backchannel.d.ts +94 -0
- package/dist/modules/auth/request-backchannel.d.ts.map +1 -0
- package/dist/modules/auth/request-backchannel.js +206 -0
- package/dist/modules/auth/request-backchannel.js.map +1 -0
- package/dist/modules/auth/request-middleware.d.ts +438 -0
- package/dist/modules/auth/request-middleware.d.ts.map +1 -0
- package/dist/modules/auth/request-middleware.js +650 -0
- package/dist/modules/auth/request-middleware.js.map +1 -0
- package/dist/modules/auth/service-token.d.ts +8 -7
- package/dist/modules/auth/service-token.d.ts.map +1 -1
- package/dist/modules/auth/service-token.js +8 -7
- package/dist/modules/auth/service-token.js.map +1 -1
- package/dist/modules/auth/sveltekit.d.ts +1 -1
- package/dist/modules/auth/sveltekit.d.ts.map +1 -1
- package/dist/modules/auth/sveltekit.js +1 -1
- package/dist/modules/auth/sveltekit.js.map +1 -1
- package/dist/namespaces.d.ts +1 -1
- package/dist/server/handlers/export.js +1 -1
- package/dist/server/handlers/export.js.map +1 -1
- package/dist/server/handlers/workspace.d.ts +1 -1
- package/dist/server/handlers/workspace.d.ts.map +1 -1
- package/dist/server/handlers/workspace.js +3 -4
- package/dist/server/handlers/workspace.js.map +1 -1
- package/dist/server/index.d.ts +5 -12
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/instance-pool.d.ts.map +1 -1
- package/dist/server/instance-pool.js +1 -0
- package/dist/server/instance-pool.js.map +1 -1
- package/dist/server/namespace-router.d.ts +1 -1
- package/dist/server/namespace-router.js +1 -1
- package/dist/server/rpc-handler.d.ts +2 -9
- package/dist/server/rpc-handler.d.ts.map +1 -1
- package/dist/server/rpc-handler.js +2 -9
- package/dist/server/rpc-handler.js.map +1 -1
- package/docs/ADR-001-sdk-design.md +3 -3
- package/docs/ADR-004-product-registry.md +1 -1
- package/docs/ADR-005-hall-integration.md +1 -1
- package/docs/ADR-006-rpc-cache.md +2 -2
- package/docs/IMPLEMENTATION-PLAN.md +7 -7
- package/docs/KIT-APP-GUIDE.md +100 -99
- package/docs/USAGE.md +30 -40
- package/docs/kit-sdk-guide.md +59 -60
- package/package.json +2 -7
- package/dist/server/hono-router.d.ts +0 -70
- package/dist/server/hono-router.d.ts.map +0 -1
- package/dist/server/hono-router.js +0 -167
- package/dist/server/hono-router.js.map +0 -1
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module modules/auth/backchannel
|
|
3
|
-
* @description OIDC back-channel logout
|
|
3
|
+
* @description Shared types for OIDC back-channel logout handlers.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* the identified user, ensuring immediate logout across all products.
|
|
5
|
+
* The framework-agnostic handler (`createRequestBackchannelLogoutHandler`) lives in
|
|
6
|
+
* `request-backchannel.ts` and imports these types. This module provides the shared
|
|
7
|
+
* configuration interface and the minimal better-auth API surface needed for session
|
|
8
|
+
* revocation.
|
|
10
9
|
*
|
|
11
10
|
* ## Protocol
|
|
12
11
|
*
|
|
@@ -17,20 +16,22 @@
|
|
|
17
16
|
* 4. Handler deletes all better-auth sessions for the `sub` (user ID) claim
|
|
18
17
|
* 5. Returns 200 on success, 400 for malformed tokens, 401 for bad signatures
|
|
19
18
|
*
|
|
20
|
-
* ##
|
|
19
|
+
* ## Usage
|
|
21
20
|
*
|
|
22
21
|
* ```typescript
|
|
23
|
-
* import {
|
|
22
|
+
* import { createRequestBackchannelLogoutHandler } from '@soulcraft/sdk/server'
|
|
24
23
|
*
|
|
25
|
-
*
|
|
24
|
+
* const handleLogout = createRequestBackchannelLogoutHandler({
|
|
26
25
|
* auth,
|
|
27
26
|
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
28
27
|
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
29
28
|
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
30
|
-
* })
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* // SvelteKit: export const POST = ({ request }) => handleLogout(request)
|
|
32
|
+
* // Bun: if (url.pathname === '/api/auth/backchannel-logout') return handleLogout(req)
|
|
31
33
|
* ```
|
|
32
34
|
*/
|
|
33
|
-
import type { Context } from 'hono';
|
|
34
35
|
/** Minimal better-auth API surface needed for session deletion. */
|
|
35
36
|
export interface BackchannelAuthLike {
|
|
36
37
|
api: {
|
|
@@ -43,7 +44,7 @@ export interface BackchannelAuthLike {
|
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
|
-
* @description Configuration for
|
|
47
|
+
* @description Configuration for `createRequestBackchannelLogoutHandler()`.
|
|
47
48
|
*/
|
|
48
49
|
export interface BackchannelLogoutConfig {
|
|
49
50
|
/** The product's better-auth instance (used to delete sessions). */
|
|
@@ -55,31 +56,4 @@ export interface BackchannelLogoutConfig {
|
|
|
55
56
|
/** This product's OIDC client ID — used to validate the `aud` claim. */
|
|
56
57
|
clientId: string;
|
|
57
58
|
}
|
|
58
|
-
/**
|
|
59
|
-
* @description Creates a Hono route handler for the OIDC back-channel logout endpoint.
|
|
60
|
-
*
|
|
61
|
-
* Mount at `POST /api/auth/backchannel-logout`. The handler:
|
|
62
|
-
* 1. Parses the `logout_token` from the form-encoded body
|
|
63
|
-
* 2. Verifies the HS256 JWT signature using the OIDC client secret
|
|
64
|
-
* 3. Validates `iss` (must match idpUrl), `aud` (must match clientId),
|
|
65
|
-
* and `events` (must contain the back-channel logout event URI)
|
|
66
|
-
* 4. Calls `auth.api.revokeUserSessions({ body: { userId: sub } })` to
|
|
67
|
-
* immediately invalidate all sessions for the identified user
|
|
68
|
-
* 5. Returns 200 on success, 400 for malformed/missing token, 401 for
|
|
69
|
-
* invalid signature or failed claims validation
|
|
70
|
-
*
|
|
71
|
-
* @param config - Auth instance, client secret, IdP URL, and client ID.
|
|
72
|
-
* @returns A Hono-compatible request handler function.
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```typescript
|
|
76
|
-
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
77
|
-
* auth,
|
|
78
|
-
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
79
|
-
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
80
|
-
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
81
|
-
* }))
|
|
82
|
-
* ```
|
|
83
|
-
*/
|
|
84
|
-
export declare function createBackchannelLogoutHandler(config: BackchannelLogoutConfig): (c: Context) => Promise<Response>;
|
|
85
59
|
//# sourceMappingURL=backchannel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backchannel.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/backchannel.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"backchannel.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/backchannel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH,mEAAmE;AACnE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE;QACH,kBAAkB,CAAC,IAAI,EAAE;YAAE,IAAI,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAC5F,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,IAAI,EAAE,mBAAmB,CAAA;IACzB,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAA;IACd,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAA;CACjB"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module modules/auth/backchannel
|
|
3
|
-
* @description OIDC back-channel logout
|
|
3
|
+
* @description Shared types for OIDC back-channel logout handlers.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* the identified user, ensuring immediate logout across all products.
|
|
5
|
+
* The framework-agnostic handler (`createRequestBackchannelLogoutHandler`) lives in
|
|
6
|
+
* `request-backchannel.ts` and imports these types. This module provides the shared
|
|
7
|
+
* configuration interface and the minimal better-auth API surface needed for session
|
|
8
|
+
* revocation.
|
|
10
9
|
*
|
|
11
10
|
* ## Protocol
|
|
12
11
|
*
|
|
@@ -17,152 +16,21 @@
|
|
|
17
16
|
* 4. Handler deletes all better-auth sessions for the `sub` (user ID) claim
|
|
18
17
|
* 5. Returns 200 on success, 400 for malformed tokens, 401 for bad signatures
|
|
19
18
|
*
|
|
20
|
-
* ##
|
|
19
|
+
* ## Usage
|
|
21
20
|
*
|
|
22
21
|
* ```typescript
|
|
23
|
-
* import {
|
|
22
|
+
* import { createRequestBackchannelLogoutHandler } from '@soulcraft/sdk/server'
|
|
24
23
|
*
|
|
25
|
-
*
|
|
24
|
+
* const handleLogout = createRequestBackchannelLogoutHandler({
|
|
26
25
|
* auth,
|
|
27
26
|
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
28
27
|
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
29
28
|
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
30
|
-
* })
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
// The OIDC back-channel logout events claim URI.
|
|
34
|
-
const BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';
|
|
35
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
-
// JWT verification helpers (Web Crypto API — no external deps)
|
|
37
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
38
|
-
/**
|
|
39
|
-
* Verify an HS256 JWT using the Web Crypto API.
|
|
40
|
-
*
|
|
41
|
-
* @param token - Raw JWT string (`header.payload.signature`).
|
|
42
|
-
* @param secret - HMAC secret for signature verification.
|
|
43
|
-
* @returns The decoded payload if the signature is valid, or null.
|
|
44
|
-
*/
|
|
45
|
-
async function verifyHS256JWT(token, secret) {
|
|
46
|
-
const parts = token.split('.');
|
|
47
|
-
if (parts.length !== 3)
|
|
48
|
-
return null;
|
|
49
|
-
const [headerB64, payloadB64, sigB64] = parts;
|
|
50
|
-
// Import the HMAC key
|
|
51
|
-
let key;
|
|
52
|
-
try {
|
|
53
|
-
key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']);
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
// Verify signature over `header.payload`
|
|
59
|
-
const signingInput = `${headerB64}.${payloadB64}`;
|
|
60
|
-
let sigBytes;
|
|
61
|
-
try {
|
|
62
|
-
sigBytes = Uint8Array.from(atob(sigB64.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
const valid = await crypto.subtle.verify('HMAC', key, sigBytes.buffer, new TextEncoder().encode(signingInput));
|
|
68
|
-
if (!valid)
|
|
69
|
-
return null;
|
|
70
|
-
// Decode payload
|
|
71
|
-
try {
|
|
72
|
-
const padded = payloadB64.replace(/-/g, '+').replace(/_/g, '/') +
|
|
73
|
-
'=='.slice(0, (4 - (payloadB64.length % 4)) % 4);
|
|
74
|
-
return JSON.parse(atob(padded));
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
81
|
-
// createBackchannelLogoutHandler
|
|
82
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
83
|
-
/**
|
|
84
|
-
* @description Creates a Hono route handler for the OIDC back-channel logout endpoint.
|
|
85
|
-
*
|
|
86
|
-
* Mount at `POST /api/auth/backchannel-logout`. The handler:
|
|
87
|
-
* 1. Parses the `logout_token` from the form-encoded body
|
|
88
|
-
* 2. Verifies the HS256 JWT signature using the OIDC client secret
|
|
89
|
-
* 3. Validates `iss` (must match idpUrl), `aud` (must match clientId),
|
|
90
|
-
* and `events` (must contain the back-channel logout event URI)
|
|
91
|
-
* 4. Calls `auth.api.revokeUserSessions({ body: { userId: sub } })` to
|
|
92
|
-
* immediately invalidate all sessions for the identified user
|
|
93
|
-
* 5. Returns 200 on success, 400 for malformed/missing token, 401 for
|
|
94
|
-
* invalid signature or failed claims validation
|
|
29
|
+
* })
|
|
95
30
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* ```typescript
|
|
101
|
-
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
102
|
-
* auth,
|
|
103
|
-
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
104
|
-
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
105
|
-
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
106
|
-
* }))
|
|
31
|
+
* // SvelteKit: export const POST = ({ request }) => handleLogout(request)
|
|
32
|
+
* // Bun: if (url.pathname === '/api/auth/backchannel-logout') return handleLogout(req)
|
|
107
33
|
* ```
|
|
108
34
|
*/
|
|
109
|
-
export
|
|
110
|
-
const idpOrigin = config.idpUrl.replace(/\/$/, '');
|
|
111
|
-
return async function backchannelLogoutHandler(c) {
|
|
112
|
-
// Parse the logout_token from the form-encoded body
|
|
113
|
-
let logoutToken = null;
|
|
114
|
-
try {
|
|
115
|
-
const contentType = c.req.header('content-type') ?? '';
|
|
116
|
-
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
117
|
-
const body = await c.req.parseBody();
|
|
118
|
-
logoutToken = body['logout_token'] ?? null;
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
// Also accept JSON body for easier testing
|
|
122
|
-
const body = await c.req.json();
|
|
123
|
-
logoutToken = body['logout_token'] ?? null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return c.json({ error: 'Failed to parse request body' }, 400);
|
|
128
|
-
}
|
|
129
|
-
if (!logoutToken || typeof logoutToken !== 'string') {
|
|
130
|
-
return c.json({ error: 'Missing logout_token' }, 400);
|
|
131
|
-
}
|
|
132
|
-
// Verify the JWT
|
|
133
|
-
const payload = await verifyHS256JWT(logoutToken, config.clientSecret);
|
|
134
|
-
if (!payload) {
|
|
135
|
-
return c.json({ error: 'Invalid logout_token signature' }, 401);
|
|
136
|
-
}
|
|
137
|
-
// Validate issuer
|
|
138
|
-
if (payload['iss'] !== idpOrigin) {
|
|
139
|
-
return c.json({ error: 'Invalid issuer' }, 401);
|
|
140
|
-
}
|
|
141
|
-
// Validate audience — may be a string or array of strings
|
|
142
|
-
const aud = payload['aud'];
|
|
143
|
-
const audList = Array.isArray(aud) ? aud : [String(aud ?? '')];
|
|
144
|
-
if (!audList.includes(config.clientId)) {
|
|
145
|
-
return c.json({ error: 'Invalid audience' }, 401);
|
|
146
|
-
}
|
|
147
|
-
// Validate events claim
|
|
148
|
-
const events = payload['events'];
|
|
149
|
-
if (!events || !(BACKCHANNEL_LOGOUT_EVENT in events)) {
|
|
150
|
-
return c.json({ error: 'Missing backchannel logout event' }, 400);
|
|
151
|
-
}
|
|
152
|
-
// Extract the subject user ID
|
|
153
|
-
const sub = payload['sub'];
|
|
154
|
-
if (!sub || typeof sub !== 'string') {
|
|
155
|
-
return c.json({ error: 'Missing sub claim' }, 400);
|
|
156
|
-
}
|
|
157
|
-
// Revoke all sessions for this user
|
|
158
|
-
try {
|
|
159
|
-
await config.auth.api.revokeUserSessions({ body: { userId: sub } });
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
console.error(`[SDK/backchannel] Failed to revoke sessions for user ${sub}:`, err);
|
|
163
|
-
return c.json({ error: 'Failed to revoke sessions' }, 500);
|
|
164
|
-
}
|
|
165
|
-
return c.json({ ok: true }, 200);
|
|
166
|
-
};
|
|
167
|
-
}
|
|
35
|
+
export {};
|
|
168
36
|
//# sourceMappingURL=backchannel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backchannel.js","sourceRoot":"","sources":["../../../src/modules/auth/backchannel.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"backchannel.js","sourceRoot":"","sources":["../../../src/modules/auth/backchannel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module modules/auth/middleware
|
|
3
|
-
* @description
|
|
4
|
-
*
|
|
3
|
+
* @description Session verification factories and shared auth types for Soulcraft
|
|
4
|
+
* product backends.
|
|
5
5
|
*
|
|
6
6
|
* ## Session verification strategies
|
|
7
7
|
*
|
|
8
|
-
* All products
|
|
9
|
-
* selects the right session verifier for its deployment context:
|
|
8
|
+
* All products select the right session verifier for their deployment context:
|
|
10
9
|
*
|
|
11
10
|
* ```
|
|
12
11
|
* Production (all products):
|
|
@@ -14,41 +13,41 @@
|
|
|
14
13
|
*
|
|
15
14
|
* Development (all products):
|
|
16
15
|
* createDevSessionVerifier({ role: 'owner' }) // auto-login, no OAuth needed
|
|
17
|
-
*
|
|
18
|
-
* Workshop standalone (legacy / local OAuth):
|
|
19
|
-
* createAuthMiddleware(betterAuthInstance) // BetterAuthLike overload
|
|
20
16
|
* ```
|
|
21
17
|
*
|
|
22
|
-
* ## Dev and guest
|
|
18
|
+
* ## Dev and guest cookie verifiers
|
|
19
|
+
*
|
|
20
|
+
* - `createDevCookieVerifier` — reads the dev session cookie issued by
|
|
21
|
+
* `createRequestDevLoginHandler` (from `request-middleware.ts`).
|
|
22
|
+
* - `createGuestCookieVerifier` — reads the guest session cookie issued by
|
|
23
|
+
* `createRequestGuestSessionHandler` (from `request-middleware.ts`).
|
|
23
24
|
*
|
|
24
|
-
* -
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* ## Framework-agnostic middleware
|
|
26
|
+
*
|
|
27
|
+
* Use `createRequestAuthMiddleware` from `request-middleware.ts` for the
|
|
28
|
+
* framework-agnostic middleware that works with any Web Standard Request/Response
|
|
29
|
+
* server (SvelteKit, Bun, Deno, Cloudflare Workers, etc.).
|
|
29
30
|
*
|
|
30
31
|
* @example Production setup (Venue / Academy)
|
|
31
32
|
* ```typescript
|
|
32
|
-
* import {
|
|
33
|
+
* import {
|
|
34
|
+
* createRequestAuthMiddleware,
|
|
35
|
+
* createRemoteSessionVerifier,
|
|
36
|
+
* getUser,
|
|
37
|
+
* } from '@soulcraft/sdk/server'
|
|
33
38
|
*
|
|
34
39
|
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
35
|
-
* const { requireAuth
|
|
40
|
+
* const { requireAuth } = createRequestAuthMiddleware(verifySession)
|
|
36
41
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
42
|
+
* // SvelteKit hooks:
|
|
43
|
+
* export const handle = async ({ event, resolve }) => {
|
|
44
|
+
* const response = await requireAuth(event.request, () => resolve(event))
|
|
45
|
+
* event.locals.user = getUser(event.request)
|
|
46
|
+
* return response
|
|
47
|
+
* }
|
|
40
48
|
* ```
|
|
41
49
|
*/
|
|
42
50
|
import type { SoulcraftSessionUser, SoulcraftSession } from './types.js';
|
|
43
|
-
import type { Context, Next } from 'hono';
|
|
44
|
-
/** The Hono context variable key where the resolved user is stored. */
|
|
45
|
-
export declare const AUTH_USER_KEY: "user";
|
|
46
|
-
/** Hono context type with the resolved Soulcraft user variable. */
|
|
47
|
-
export type AuthContext = Context<{
|
|
48
|
-
Variables: {
|
|
49
|
-
[AUTH_USER_KEY]: SoulcraftSessionUser | null;
|
|
50
|
-
};
|
|
51
|
-
}>;
|
|
52
51
|
/** Minimal better-auth API surface the middleware depends on. */
|
|
53
52
|
export interface BetterAuthLike {
|
|
54
53
|
api: {
|
|
@@ -65,15 +64,14 @@ export interface BetterAuthLike {
|
|
|
65
64
|
}
|
|
66
65
|
/**
|
|
67
66
|
* A session verifier function — the common abstraction for session resolution
|
|
68
|
-
* across all products
|
|
67
|
+
* across all products.
|
|
69
68
|
*
|
|
70
69
|
* Returned by `createRemoteSessionVerifier` and `createDevSessionVerifier`.
|
|
71
|
-
* `
|
|
72
|
-
* standalone mode) or a `SessionVerifier` function (all other products and modes).
|
|
70
|
+
* Pass to `createRequestAuthMiddleware` for the framework-agnostic middleware.
|
|
73
71
|
*/
|
|
74
72
|
export type SessionVerifier = (cookieHeader: string) => Promise<SoulcraftSession | null>;
|
|
75
73
|
/**
|
|
76
|
-
* Options for `
|
|
74
|
+
* Options for `createRequestAuthMiddleware()` and legacy middleware.
|
|
77
75
|
*/
|
|
78
76
|
export interface AuthMiddlewareOptions {
|
|
79
77
|
/**
|
|
@@ -85,22 +83,6 @@ export interface AuthMiddlewareOptions {
|
|
|
85
83
|
*/
|
|
86
84
|
devAutoLogin?: boolean;
|
|
87
85
|
}
|
|
88
|
-
/**
|
|
89
|
-
* The object returned by `createAuthMiddleware()`.
|
|
90
|
-
*/
|
|
91
|
-
export interface AuthMiddleware {
|
|
92
|
-
/**
|
|
93
|
-
* Require authentication. Resolves the session from request cookies. If the
|
|
94
|
-
* session is valid, attaches the typed user to the Hono context under the
|
|
95
|
-
* `'user'` key and calls `next()`. Returns HTTP 401 if unauthenticated.
|
|
96
|
-
*/
|
|
97
|
-
requireAuth: (c: AuthContext, next: Next) => Promise<void | Response>;
|
|
98
|
-
/**
|
|
99
|
-
* Optional authentication. Resolves the session if one exists, but does not
|
|
100
|
-
* reject unauthenticated requests. User will be `null` for anonymous requests.
|
|
101
|
-
*/
|
|
102
|
-
optionalAuth: (c: AuthContext, next: Next) => Promise<void | Response>;
|
|
103
|
-
}
|
|
104
86
|
/**
|
|
105
87
|
* Options for `createRemoteSessionVerifier()`.
|
|
106
88
|
*/
|
|
@@ -133,7 +115,7 @@ export interface DevSessionVerifierOptions {
|
|
|
133
115
|
name?: string;
|
|
134
116
|
}
|
|
135
117
|
/**
|
|
136
|
-
* Options for `
|
|
118
|
+
* Options for `createRequestDevLoginHandler()`.
|
|
137
119
|
*/
|
|
138
120
|
export interface DevLoginHandlerOptions {
|
|
139
121
|
/**
|
|
@@ -154,7 +136,7 @@ export interface DevLoginHandlerOptions {
|
|
|
154
136
|
maxAgeSeconds?: number;
|
|
155
137
|
}
|
|
156
138
|
/**
|
|
157
|
-
* Options for `
|
|
139
|
+
* Options for `createRequestGuestSessionHandler()`.
|
|
158
140
|
*/
|
|
159
141
|
export interface GuestSessionHandlerOptions {
|
|
160
142
|
/**
|
|
@@ -176,39 +158,6 @@ export interface GuestSessionHandlerOptions {
|
|
|
176
158
|
*/
|
|
177
159
|
onGuestCreated?: (guestId: string) => Promise<void> | void;
|
|
178
160
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Creates Hono auth middleware from a `SessionVerifier` function or a `BetterAuthLike`
|
|
181
|
-
* instance.
|
|
182
|
-
*
|
|
183
|
-
* **Preferred form (all products in OIDC-client mode):**
|
|
184
|
-
* Pass a `SessionVerifier` returned by `createRemoteSessionVerifier` or
|
|
185
|
-
* `createDevSessionVerifier`. The middleware reads the request cookie header and
|
|
186
|
-
* passes it to the verifier.
|
|
187
|
-
*
|
|
188
|
-
* **Legacy form (Workshop standalone mode):**
|
|
189
|
-
* Pass a `better-auth` instance directly. The middleware calls `auth.api.getSession`.
|
|
190
|
-
* In non-production environments and when `devAutoLogin` is enabled, a synthetic dev
|
|
191
|
-
* user is injected on failed lookups so local dev works without OAuth.
|
|
192
|
-
*
|
|
193
|
-
* Both forms return identical `{ requireAuth, optionalAuth }` middleware.
|
|
194
|
-
*
|
|
195
|
-
* @param authOrVerifier - A `better-auth` instance or a `SessionVerifier` function.
|
|
196
|
-
* @param options - Optional middleware configuration (only applies to `BetterAuthLike` form).
|
|
197
|
-
* @returns Middleware pair: `{ requireAuth, optionalAuth }`.
|
|
198
|
-
*
|
|
199
|
-
* @example Verifier form (Venue / Academy / Workshop in OIDC mode)
|
|
200
|
-
* ```typescript
|
|
201
|
-
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
202
|
-
* const { requireAuth } = createAuthMiddleware(verifySession)
|
|
203
|
-
* ```
|
|
204
|
-
*
|
|
205
|
-
* @example BetterAuth form (Workshop dev standalone)
|
|
206
|
-
* ```typescript
|
|
207
|
-
* import { auth } from './better-auth.js'
|
|
208
|
-
* const { requireAuth } = createAuthMiddleware(auth)
|
|
209
|
-
* ```
|
|
210
|
-
*/
|
|
211
|
-
export declare function createAuthMiddleware(authOrVerifier: BetterAuthLike | SessionVerifier, options?: AuthMiddlewareOptions): AuthMiddleware;
|
|
212
161
|
/**
|
|
213
162
|
* Creates a cached remote session verifier that proxies session lookups to
|
|
214
163
|
* the central IdP at `auth.soulcraft.com`.
|
|
@@ -220,10 +169,10 @@ export declare function createAuthMiddleware(authOrVerifier: BetterAuthLike | Se
|
|
|
220
169
|
* The verifier sends the cookie header to the IdP's `/api/auth/get-session` endpoint
|
|
221
170
|
* and returns the resolved `SoulcraftSession` or `null` if the session is invalid.
|
|
222
171
|
*
|
|
223
|
-
* Pass the returned function
|
|
172
|
+
* Pass the returned function to `createRequestAuthMiddleware`:
|
|
224
173
|
* ```typescript
|
|
225
174
|
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
226
|
-
* const { requireAuth } =
|
|
175
|
+
* const { requireAuth } = createRequestAuthMiddleware(verifySession)
|
|
227
176
|
* ```
|
|
228
177
|
*
|
|
229
178
|
* @param options - IdP URL, cache TTL, and max cache size.
|
|
@@ -236,8 +185,8 @@ export declare function createAuthMiddleware(authOrVerifier: BetterAuthLike | Se
|
|
|
236
185
|
* cacheTtlMs: 30_000,
|
|
237
186
|
* })
|
|
238
187
|
*
|
|
239
|
-
* const session = await verifySession(
|
|
240
|
-
* if (!session) return
|
|
188
|
+
* const session = await verifySession(request.headers.get('cookie') ?? '')
|
|
189
|
+
* if (!session) return new Response('Unauthorized', { status: 401 })
|
|
241
190
|
* ```
|
|
242
191
|
*/
|
|
243
192
|
export declare function createRemoteSessionVerifier(options: RemoteSessionVerifierOptions): SessionVerifier;
|
|
@@ -255,7 +204,7 @@ export declare function createRemoteSessionVerifier(options: RemoteSessionVerifi
|
|
|
255
204
|
* ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
|
|
256
205
|
* : createDevSessionVerifier({ role: 'owner' })
|
|
257
206
|
*
|
|
258
|
-
* const { requireAuth } =
|
|
207
|
+
* const { requireAuth } = createRequestAuthMiddleware(verifySession)
|
|
259
208
|
* ```
|
|
260
209
|
*
|
|
261
210
|
* **Never use in production.** The verifier performs no validation whatsoever.
|
|
@@ -278,34 +227,9 @@ export declare function createRemoteSessionVerifier(options: RemoteSessionVerifi
|
|
|
278
227
|
*/
|
|
279
228
|
export declare function createDevSessionVerifier(options?: DevSessionVerifierOptions): SessionVerifier;
|
|
280
229
|
/**
|
|
281
|
-
* Creates a
|
|
230
|
+
* Creates a session verifier that reads the cookie issued by `createRequestDevLoginHandler`.
|
|
282
231
|
*
|
|
283
|
-
*
|
|
284
|
-
* development. Accepts `?role=<platformRole>` and optional `?email=` / `?name=`
|
|
285
|
-
* query params. Issues a signed base64url session cookie that `createAuthMiddleware`
|
|
286
|
-
* (when used with a `SessionVerifier` that reads dev cookies) can resolve.
|
|
287
|
-
*
|
|
288
|
-
* **Guards against production use:** the handler returns HTTP 404 when
|
|
289
|
-
* `NODE_ENV === 'production'` — it is safe to leave mounted in all environments.
|
|
290
|
-
*
|
|
291
|
-
* @param options - Allowed roles, cookie name, and max-age.
|
|
292
|
-
* @returns A Hono-compatible request handler `(c: Context) => Response`.
|
|
293
|
-
*
|
|
294
|
-
* @example
|
|
295
|
-
* ```typescript
|
|
296
|
-
* import { createDevLoginHandler } from '@soulcraft/sdk/server'
|
|
297
|
-
*
|
|
298
|
-
* // In your Hono server setup:
|
|
299
|
-
* app.get('/api/dev/login', createDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] }))
|
|
300
|
-
*
|
|
301
|
-
* // Usage: GET /api/dev/login?role=staff → sets cookie + redirects to /
|
|
302
|
-
* ```
|
|
303
|
-
*/
|
|
304
|
-
export declare function createDevLoginHandler(options?: DevLoginHandlerOptions): (c: Context) => Response | Promise<Response>;
|
|
305
|
-
/**
|
|
306
|
-
* Creates a session verifier that reads the cookie issued by `createDevLoginHandler`.
|
|
307
|
-
*
|
|
308
|
-
* Use this together with `createDevLoginHandler` when you want dev role-switching
|
|
232
|
+
* Use this together with `createRequestDevLoginHandler` when you want dev role-switching
|
|
309
233
|
* (e.g. clicking "Login as Staff" in a dev UI) rather than a fixed synthetic user.
|
|
310
234
|
*
|
|
311
235
|
* The verifier decodes the base64url cookie value and returns the embedded session.
|
|
@@ -318,52 +242,16 @@ export declare function createDevLoginHandler(options?: DevLoginHandlerOptions):
|
|
|
318
242
|
* const verifySession = createDevSessionVerifier({ role: 'owner' })
|
|
319
243
|
*
|
|
320
244
|
* // Option B: Role-switching dev login UI
|
|
321
|
-
*
|
|
245
|
+
* const loginHandler = createRequestDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] })
|
|
322
246
|
* const verifySession = createDevCookieVerifier()
|
|
323
247
|
* ```
|
|
324
248
|
*
|
|
325
|
-
* @param cookieName - Must match the `cookieName` passed to `
|
|
326
|
-
* @returns A `SessionVerifier` compatible with `
|
|
249
|
+
* @param cookieName - Must match the `cookieName` passed to `createRequestDevLoginHandler`. Default: `'soulcraft_dev_session'`.
|
|
250
|
+
* @returns A `SessionVerifier` compatible with `createRequestAuthMiddleware`.
|
|
327
251
|
*/
|
|
328
252
|
export declare function createDevCookieVerifier(cookieName?: string): SessionVerifier;
|
|
329
253
|
/**
|
|
330
|
-
* Creates a
|
|
331
|
-
*
|
|
332
|
-
* Venue visitors can browse and initiate bookings without creating an account.
|
|
333
|
-
* This handler mounts at e.g. `/api/guest/session` and issues a session cookie
|
|
334
|
-
* with `platformRole: 'guest'` and a unique guest ID on each call (if no valid
|
|
335
|
-
* guest session already exists).
|
|
336
|
-
*
|
|
337
|
-
* The guest session cookie can be verified using `createGuestCookieVerifier`,
|
|
338
|
-
* which returns a `SessionVerifier` compatible with `createAuthMiddleware`.
|
|
339
|
-
*
|
|
340
|
-
* @param options - Cookie name, max-age, and optional `onGuestCreated` callback.
|
|
341
|
-
* @returns A Hono-compatible request handler.
|
|
342
|
-
*
|
|
343
|
-
* @example
|
|
344
|
-
* ```typescript
|
|
345
|
-
* import { createGuestSessionHandler, createGuestCookieVerifier, createAuthMiddleware } from '@soulcraft/sdk/server'
|
|
346
|
-
*
|
|
347
|
-
* // Issue guest sessions
|
|
348
|
-
* app.post('/api/guest/session', createGuestSessionHandler({
|
|
349
|
-
* onGuestCreated: async (guestId) => {
|
|
350
|
-
* await db.guests.insert({ id: guestId, createdAt: new Date() })
|
|
351
|
-
* },
|
|
352
|
-
* }))
|
|
353
|
-
*
|
|
354
|
-
* // Verify guest sessions in optional auth (guests can browse)
|
|
355
|
-
* const verifyGuest = createGuestCookieVerifier()
|
|
356
|
-
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
357
|
-
*
|
|
358
|
-
* // Compose: check real session first, fall back to guest
|
|
359
|
-
* const { optionalAuth } = createAuthMiddleware(async (cookie) =>
|
|
360
|
-
* await verifySession(cookie) ?? await verifyGuest(cookie)
|
|
361
|
-
* )
|
|
362
|
-
* ```
|
|
363
|
-
*/
|
|
364
|
-
export declare function createGuestSessionHandler(options?: GuestSessionHandlerOptions): (c: Context) => Promise<Response>;
|
|
365
|
-
/**
|
|
366
|
-
* Creates a session verifier that reads the cookie issued by `createGuestSessionHandler`.
|
|
254
|
+
* Creates a session verifier that reads the cookie issued by `createRequestGuestSessionHandler`.
|
|
367
255
|
*
|
|
368
256
|
* Returns the guest `SoulcraftSession` or `null` if no valid guest cookie is present.
|
|
369
257
|
* Compose with `createRemoteSessionVerifier` to allow both authenticated and guest access:
|
|
@@ -372,13 +260,13 @@ export declare function createGuestSessionHandler(options?: GuestSessionHandlerO
|
|
|
372
260
|
* const verifyReal = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
373
261
|
* const verifyGuest = createGuestCookieVerifier()
|
|
374
262
|
*
|
|
375
|
-
* const { optionalAuth } =
|
|
263
|
+
* const { optionalAuth } = createRequestAuthMiddleware(async (cookie) =>
|
|
376
264
|
* await verifyReal(cookie) ?? await verifyGuest(cookie)
|
|
377
265
|
* )
|
|
378
266
|
* ```
|
|
379
267
|
*
|
|
380
|
-
* @param cookieName - Must match the `cookieName` passed to `
|
|
381
|
-
* @returns A `SessionVerifier` compatible with `
|
|
268
|
+
* @param cookieName - Must match the `cookieName` passed to `createRequestGuestSessionHandler`. Default: `'soulcraft_guest_session'`.
|
|
269
|
+
* @returns A `SessionVerifier` compatible with `createRequestAuthMiddleware`.
|
|
382
270
|
*/
|
|
383
271
|
export declare function createGuestCookieVerifier(cookieName?: string): SessionVerifier;
|
|
384
272
|
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/middleware.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAMxE,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE;QACH,UAAU,CAAC,IAAI,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAAC,OAAO,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;aAAE,CAAA;SAAE,GAAG,IAAI,CAAC,CAAA;KACtJ,CAAA;CACF;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;AAExF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAA;IAC3C;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,EAAE,CAAA;IACrD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC3D;AA+BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B,GACpC,eAAe,CAkEjB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,yBAA8B,GACtC,eAAe,CAsBjB;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,SAA0B,GACnC,eAAe,CAMjB;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,SAA4B,GACrC,eAAe,CAMjB"}
|