@soulcraft/sdk 2.8.0 → 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 -52
- package/dist/modules/auth/backchannel.d.ts.map +1 -1
- package/dist/modules/auth/backchannel.js +12 -147
- package/dist/modules/auth/backchannel.js.map +1 -1
- package/dist/modules/auth/middleware.d.ts +45 -185
- package/dist/modules/auth/middleware.d.ts.map +1 -1
- package/dist/modules/auth/middleware.js +40 -331
- 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 +39 -6
- package/dist/modules/auth/request-backchannel.d.ts.map +1 -1
- package/dist/modules/auth/request-backchannel.js +15 -5
- package/dist/modules/auth/request-backchannel.js.map +1 -1
- package/dist/modules/auth/request-middleware.d.ts +267 -24
- package/dist/modules/auth/request-middleware.d.ts.map +1 -1
- package/dist/modules/auth/request-middleware.js +264 -23
- package/dist/modules/auth/request-middleware.js.map +1 -1
- 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 +4 -13
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -11
- package/dist/server/index.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 +1 -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,29 +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
|
-
/** Minimal Hono-compatible context for the backchannel handler. */
|
|
34
|
-
interface HonoContext {
|
|
35
|
-
req: {
|
|
36
|
-
raw: Request;
|
|
37
|
-
json<T>(): Promise<T>;
|
|
38
|
-
header(name: string): string | undefined;
|
|
39
|
-
parseBody(): Promise<Record<string, string | File>>;
|
|
40
|
-
};
|
|
41
|
-
json(data: unknown, status?: number): Response;
|
|
42
|
-
}
|
|
43
35
|
/** Minimal better-auth API surface needed for session deletion. */
|
|
44
36
|
export interface BackchannelAuthLike {
|
|
45
37
|
api: {
|
|
@@ -52,7 +44,7 @@ export interface BackchannelAuthLike {
|
|
|
52
44
|
};
|
|
53
45
|
}
|
|
54
46
|
/**
|
|
55
|
-
* @description Configuration for
|
|
47
|
+
* @description Configuration for `createRequestBackchannelLogoutHandler()`.
|
|
56
48
|
*/
|
|
57
49
|
export interface BackchannelLogoutConfig {
|
|
58
50
|
/** The product's better-auth instance (used to delete sessions). */
|
|
@@ -64,35 +56,4 @@ export interface BackchannelLogoutConfig {
|
|
|
64
56
|
/** This product's OIDC client ID — used to validate the `aud` claim. */
|
|
65
57
|
clientId: string;
|
|
66
58
|
}
|
|
67
|
-
/**
|
|
68
|
-
* @description Creates a Hono route handler for the OIDC back-channel logout endpoint.
|
|
69
|
-
*
|
|
70
|
-
* Mount at `POST /api/auth/backchannel-logout`. The handler:
|
|
71
|
-
* 1. Parses the `logout_token` from the form-encoded body
|
|
72
|
-
* 2. Verifies the HS256 JWT signature using the OIDC client secret
|
|
73
|
-
* 3. Validates `iss` (must match idpUrl), `aud` (must match clientId),
|
|
74
|
-
* and `events` (must contain the back-channel logout event URI)
|
|
75
|
-
* 4. Calls `auth.api.revokeUserSessions({ body: { userId: sub } })` to
|
|
76
|
-
* immediately invalidate all sessions for the identified user
|
|
77
|
-
* 5. Returns 200 on success, 400 for malformed/missing token, 401 for
|
|
78
|
-
* invalid signature or failed claims validation
|
|
79
|
-
*
|
|
80
|
-
* @param config - Auth instance, client secret, IdP URL, and client ID.
|
|
81
|
-
* @returns A Hono-compatible request handler function.
|
|
82
|
-
*
|
|
83
|
-
* @deprecated Use `createRequestBackchannelLogoutHandler` from `request-backchannel.ts` instead.
|
|
84
|
-
* The Hono-specific handler will be removed in a future major version.
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* ```typescript
|
|
88
|
-
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
89
|
-
* auth,
|
|
90
|
-
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
91
|
-
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
92
|
-
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
93
|
-
* }))
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
export declare function createBackchannelLogoutHandler(config: BackchannelLogoutConfig): (c: HonoContext) => Promise<Response>;
|
|
97
|
-
export {};
|
|
98
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,155 +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
|
-
* @deprecated Use `createRequestBackchannelLogoutHandler` from `request-backchannel.ts` instead.
|
|
100
|
-
* The Hono-specific handler will be removed in a future major version.
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* app.post('/api/auth/backchannel-logout', createBackchannelLogoutHandler({
|
|
105
|
-
* auth,
|
|
106
|
-
* clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
|
|
107
|
-
* idpUrl: process.env.SOULCRAFT_IDP_URL!,
|
|
108
|
-
* clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
|
|
109
|
-
* }))
|
|
31
|
+
* // SvelteKit: export const POST = ({ request }) => handleLogout(request)
|
|
32
|
+
* // Bun: if (url.pathname === '/api/auth/backchannel-logout') return handleLogout(req)
|
|
110
33
|
* ```
|
|
111
34
|
*/
|
|
112
|
-
export
|
|
113
|
-
const idpOrigin = config.idpUrl.replace(/\/$/, '');
|
|
114
|
-
return async function backchannelLogoutHandler(c) {
|
|
115
|
-
// Parse the logout_token from the form-encoded body
|
|
116
|
-
let logoutToken = null;
|
|
117
|
-
try {
|
|
118
|
-
const contentType = c.req.header('content-type') ?? '';
|
|
119
|
-
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
120
|
-
const body = await c.req.parseBody();
|
|
121
|
-
logoutToken = body['logout_token'] ?? null;
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
// Also accept JSON body for easier testing
|
|
125
|
-
const body = await c.req.json();
|
|
126
|
-
logoutToken = body['logout_token'] ?? null;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
return c.json({ error: 'Failed to parse request body' }, 400);
|
|
131
|
-
}
|
|
132
|
-
if (!logoutToken || typeof logoutToken !== 'string') {
|
|
133
|
-
return c.json({ error: 'Missing logout_token' }, 400);
|
|
134
|
-
}
|
|
135
|
-
// Verify the JWT
|
|
136
|
-
const payload = await verifyHS256JWT(logoutToken, config.clientSecret);
|
|
137
|
-
if (!payload) {
|
|
138
|
-
return c.json({ error: 'Invalid logout_token signature' }, 401);
|
|
139
|
-
}
|
|
140
|
-
// Validate issuer
|
|
141
|
-
if (payload['iss'] !== idpOrigin) {
|
|
142
|
-
return c.json({ error: 'Invalid issuer' }, 401);
|
|
143
|
-
}
|
|
144
|
-
// Validate audience — may be a string or array of strings
|
|
145
|
-
const aud = payload['aud'];
|
|
146
|
-
const audList = Array.isArray(aud) ? aud : [String(aud ?? '')];
|
|
147
|
-
if (!audList.includes(config.clientId)) {
|
|
148
|
-
return c.json({ error: 'Invalid audience' }, 401);
|
|
149
|
-
}
|
|
150
|
-
// Validate events claim
|
|
151
|
-
const events = payload['events'];
|
|
152
|
-
if (!events || !(BACKCHANNEL_LOGOUT_EVENT in events)) {
|
|
153
|
-
return c.json({ error: 'Missing backchannel logout event' }, 400);
|
|
154
|
-
}
|
|
155
|
-
// Extract the subject user ID
|
|
156
|
-
const sub = payload['sub'];
|
|
157
|
-
if (!sub || typeof sub !== 'string') {
|
|
158
|
-
return c.json({ error: 'Missing sub claim' }, 400);
|
|
159
|
-
}
|
|
160
|
-
// Revoke all sessions for this user
|
|
161
|
-
try {
|
|
162
|
-
await config.auth.api.revokeUserSessions({ body: { userId: sub } });
|
|
163
|
-
}
|
|
164
|
-
catch (err) {
|
|
165
|
-
console.error(`[SDK/backchannel] Failed to revoke sessions for user ${sub}:`, err);
|
|
166
|
-
return c.json({ error: 'Failed to revoke sessions' }, 500);
|
|
167
|
-
}
|
|
168
|
-
return c.json({ ok: true }, 200);
|
|
169
|
-
};
|
|
170
|
-
}
|
|
35
|
+
export {};
|
|
171
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,59 +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
|
-
/** Minimal Hono-compatible context shape used by the auth middleware. */
|
|
44
|
-
interface HonoContext<T extends {
|
|
45
|
-
Variables: Record<string, unknown>;
|
|
46
|
-
} = {
|
|
47
|
-
Variables: Record<string, unknown>;
|
|
48
|
-
}> {
|
|
49
|
-
req: {
|
|
50
|
-
raw: Request;
|
|
51
|
-
header(name: string): string | undefined;
|
|
52
|
-
query(name: string): string | undefined;
|
|
53
|
-
};
|
|
54
|
-
get<K extends keyof T['Variables']>(key: K): T['Variables'][K];
|
|
55
|
-
set<K extends keyof T['Variables']>(key: K, value: T['Variables'][K]): void;
|
|
56
|
-
json(data: unknown, status?: number): Response;
|
|
57
|
-
redirect(url: string, status?: number): Response;
|
|
58
|
-
header(name: string, value: string): void;
|
|
59
|
-
}
|
|
60
|
-
/** Hono-compatible Next function. */
|
|
61
|
-
type HonoNext = () => Promise<void>;
|
|
62
|
-
/** The Hono context variable key where the resolved user is stored. */
|
|
63
|
-
export declare const AUTH_USER_KEY: "user";
|
|
64
|
-
/** Hono-compatible context type with the resolved Soulcraft user variable. */
|
|
65
|
-
export type AuthContext = HonoContext<{
|
|
66
|
-
Variables: {
|
|
67
|
-
[AUTH_USER_KEY]: SoulcraftSessionUser | null;
|
|
68
|
-
};
|
|
69
|
-
}>;
|
|
70
51
|
/** Minimal better-auth API surface the middleware depends on. */
|
|
71
52
|
export interface BetterAuthLike {
|
|
72
53
|
api: {
|
|
@@ -83,15 +64,14 @@ export interface BetterAuthLike {
|
|
|
83
64
|
}
|
|
84
65
|
/**
|
|
85
66
|
* A session verifier function — the common abstraction for session resolution
|
|
86
|
-
* across all products
|
|
67
|
+
* across all products.
|
|
87
68
|
*
|
|
88
69
|
* Returned by `createRemoteSessionVerifier` and `createDevSessionVerifier`.
|
|
89
|
-
* `
|
|
90
|
-
* standalone mode) or a `SessionVerifier` function (all other products and modes).
|
|
70
|
+
* Pass to `createRequestAuthMiddleware` for the framework-agnostic middleware.
|
|
91
71
|
*/
|
|
92
72
|
export type SessionVerifier = (cookieHeader: string) => Promise<SoulcraftSession | null>;
|
|
93
73
|
/**
|
|
94
|
-
* Options for `
|
|
74
|
+
* Options for `createRequestAuthMiddleware()` and legacy middleware.
|
|
95
75
|
*/
|
|
96
76
|
export interface AuthMiddlewareOptions {
|
|
97
77
|
/**
|
|
@@ -103,22 +83,6 @@ export interface AuthMiddlewareOptions {
|
|
|
103
83
|
*/
|
|
104
84
|
devAutoLogin?: boolean;
|
|
105
85
|
}
|
|
106
|
-
/**
|
|
107
|
-
* The object returned by `createAuthMiddleware()`.
|
|
108
|
-
*/
|
|
109
|
-
export interface AuthMiddleware {
|
|
110
|
-
/**
|
|
111
|
-
* Require authentication. Resolves the session from request cookies. If the
|
|
112
|
-
* session is valid, attaches the typed user to the Hono context under the
|
|
113
|
-
* `'user'` key and calls `next()`. Returns HTTP 401 if unauthenticated.
|
|
114
|
-
*/
|
|
115
|
-
requireAuth: (c: AuthContext, next: HonoNext) => Promise<void | Response>;
|
|
116
|
-
/**
|
|
117
|
-
* Optional authentication. Resolves the session if one exists, but does not
|
|
118
|
-
* reject unauthenticated requests. User will be `null` for anonymous requests.
|
|
119
|
-
*/
|
|
120
|
-
optionalAuth: (c: AuthContext, next: HonoNext) => Promise<void | Response>;
|
|
121
|
-
}
|
|
122
86
|
/**
|
|
123
87
|
* Options for `createRemoteSessionVerifier()`.
|
|
124
88
|
*/
|
|
@@ -151,7 +115,7 @@ export interface DevSessionVerifierOptions {
|
|
|
151
115
|
name?: string;
|
|
152
116
|
}
|
|
153
117
|
/**
|
|
154
|
-
* Options for `
|
|
118
|
+
* Options for `createRequestDevLoginHandler()`.
|
|
155
119
|
*/
|
|
156
120
|
export interface DevLoginHandlerOptions {
|
|
157
121
|
/**
|
|
@@ -172,7 +136,7 @@ export interface DevLoginHandlerOptions {
|
|
|
172
136
|
maxAgeSeconds?: number;
|
|
173
137
|
}
|
|
174
138
|
/**
|
|
175
|
-
* Options for `
|
|
139
|
+
* Options for `createRequestGuestSessionHandler()`.
|
|
176
140
|
*/
|
|
177
141
|
export interface GuestSessionHandlerOptions {
|
|
178
142
|
/**
|
|
@@ -194,42 +158,6 @@ export interface GuestSessionHandlerOptions {
|
|
|
194
158
|
*/
|
|
195
159
|
onGuestCreated?: (guestId: string) => Promise<void> | void;
|
|
196
160
|
}
|
|
197
|
-
/**
|
|
198
|
-
* Creates Hono auth middleware from a `SessionVerifier` function or a `BetterAuthLike`
|
|
199
|
-
* instance.
|
|
200
|
-
*
|
|
201
|
-
* **Preferred form (all products in OIDC-client mode):**
|
|
202
|
-
* Pass a `SessionVerifier` returned by `createRemoteSessionVerifier` or
|
|
203
|
-
* `createDevSessionVerifier`. The middleware reads the request cookie header and
|
|
204
|
-
* passes it to the verifier.
|
|
205
|
-
*
|
|
206
|
-
* **Legacy form (Workshop standalone mode):**
|
|
207
|
-
* Pass a `better-auth` instance directly. The middleware calls `auth.api.getSession`.
|
|
208
|
-
* In non-production environments and when `devAutoLogin` is enabled, a synthetic dev
|
|
209
|
-
* user is injected on failed lookups so local dev works without OAuth.
|
|
210
|
-
*
|
|
211
|
-
* Both forms return identical `{ requireAuth, optionalAuth }` middleware.
|
|
212
|
-
*
|
|
213
|
-
* @param authOrVerifier - A `better-auth` instance or a `SessionVerifier` function.
|
|
214
|
-
* @param options - Optional middleware configuration (only applies to `BetterAuthLike` form).
|
|
215
|
-
* @returns Middleware pair: `{ requireAuth, optionalAuth }`.
|
|
216
|
-
*
|
|
217
|
-
* @example Verifier form (Venue / Academy / Workshop in OIDC mode)
|
|
218
|
-
* ```typescript
|
|
219
|
-
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
220
|
-
* const { requireAuth } = createAuthMiddleware(verifySession)
|
|
221
|
-
* ```
|
|
222
|
-
*
|
|
223
|
-
* @deprecated Use `createRequestAuthMiddleware` from `request-middleware.ts` instead.
|
|
224
|
-
* The Hono-specific middleware will be removed in a future major version.
|
|
225
|
-
*
|
|
226
|
-
* @example BetterAuth form (Workshop dev standalone)
|
|
227
|
-
* ```typescript
|
|
228
|
-
* import { auth } from './better-auth.js'
|
|
229
|
-
* const { requireAuth } = createAuthMiddleware(auth)
|
|
230
|
-
* ```
|
|
231
|
-
*/
|
|
232
|
-
export declare function createAuthMiddleware(authOrVerifier: BetterAuthLike | SessionVerifier, options?: AuthMiddlewareOptions): AuthMiddleware;
|
|
233
161
|
/**
|
|
234
162
|
* Creates a cached remote session verifier that proxies session lookups to
|
|
235
163
|
* the central IdP at `auth.soulcraft.com`.
|
|
@@ -241,10 +169,10 @@ export declare function createAuthMiddleware(authOrVerifier: BetterAuthLike | Se
|
|
|
241
169
|
* The verifier sends the cookie header to the IdP's `/api/auth/get-session` endpoint
|
|
242
170
|
* and returns the resolved `SoulcraftSession` or `null` if the session is invalid.
|
|
243
171
|
*
|
|
244
|
-
* Pass the returned function
|
|
172
|
+
* Pass the returned function to `createRequestAuthMiddleware`:
|
|
245
173
|
* ```typescript
|
|
246
174
|
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
247
|
-
* const { requireAuth } =
|
|
175
|
+
* const { requireAuth } = createRequestAuthMiddleware(verifySession)
|
|
248
176
|
* ```
|
|
249
177
|
*
|
|
250
178
|
* @param options - IdP URL, cache TTL, and max cache size.
|
|
@@ -257,8 +185,8 @@ export declare function createAuthMiddleware(authOrVerifier: BetterAuthLike | Se
|
|
|
257
185
|
* cacheTtlMs: 30_000,
|
|
258
186
|
* })
|
|
259
187
|
*
|
|
260
|
-
* const session = await verifySession(
|
|
261
|
-
* if (!session) return
|
|
188
|
+
* const session = await verifySession(request.headers.get('cookie') ?? '')
|
|
189
|
+
* if (!session) return new Response('Unauthorized', { status: 401 })
|
|
262
190
|
* ```
|
|
263
191
|
*/
|
|
264
192
|
export declare function createRemoteSessionVerifier(options: RemoteSessionVerifierOptions): SessionVerifier;
|
|
@@ -276,7 +204,7 @@ export declare function createRemoteSessionVerifier(options: RemoteSessionVerifi
|
|
|
276
204
|
* ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
|
|
277
205
|
* : createDevSessionVerifier({ role: 'owner' })
|
|
278
206
|
*
|
|
279
|
-
* const { requireAuth } =
|
|
207
|
+
* const { requireAuth } = createRequestAuthMiddleware(verifySession)
|
|
280
208
|
* ```
|
|
281
209
|
*
|
|
282
210
|
* **Never use in production.** The verifier performs no validation whatsoever.
|
|
@@ -299,37 +227,9 @@ export declare function createRemoteSessionVerifier(options: RemoteSessionVerifi
|
|
|
299
227
|
*/
|
|
300
228
|
export declare function createDevSessionVerifier(options?: DevSessionVerifierOptions): SessionVerifier;
|
|
301
229
|
/**
|
|
302
|
-
* Creates a
|
|
303
|
-
*
|
|
304
|
-
* Mount at `/api/dev/login` to get a role-switching endpoint for local
|
|
305
|
-
* development. Accepts `?role=<platformRole>` and optional `?email=` / `?name=`
|
|
306
|
-
* query params. Issues a signed base64url session cookie that `createAuthMiddleware`
|
|
307
|
-
* (when used with a `SessionVerifier` that reads dev cookies) can resolve.
|
|
308
|
-
*
|
|
309
|
-
* **Guards against production use:** the handler returns HTTP 404 when
|
|
310
|
-
* `NODE_ENV === 'production'` — it is safe to leave mounted in all environments.
|
|
311
|
-
*
|
|
312
|
-
* @param options - Allowed roles, cookie name, and max-age.
|
|
313
|
-
* @returns A Hono-compatible request handler `(c: HonoContext) => Response`.
|
|
314
|
-
*
|
|
315
|
-
* @deprecated Use `createRequestDevLoginHandler` from `request-middleware.ts` instead.
|
|
316
|
-
* The Hono-specific handler will be removed in a future major version.
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```typescript
|
|
320
|
-
* import { createDevLoginHandler } from '@soulcraft/sdk/server'
|
|
230
|
+
* Creates a session verifier that reads the cookie issued by `createRequestDevLoginHandler`.
|
|
321
231
|
*
|
|
322
|
-
*
|
|
323
|
-
* app.get('/api/dev/login', createDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] }))
|
|
324
|
-
*
|
|
325
|
-
* // Usage: GET /api/dev/login?role=staff → sets cookie + redirects to /
|
|
326
|
-
* ```
|
|
327
|
-
*/
|
|
328
|
-
export declare function createDevLoginHandler(options?: DevLoginHandlerOptions): (c: HonoContext) => Response | Promise<Response>;
|
|
329
|
-
/**
|
|
330
|
-
* Creates a session verifier that reads the cookie issued by `createDevLoginHandler`.
|
|
331
|
-
*
|
|
332
|
-
* Use this together with `createDevLoginHandler` when you want dev role-switching
|
|
232
|
+
* Use this together with `createRequestDevLoginHandler` when you want dev role-switching
|
|
333
233
|
* (e.g. clicking "Login as Staff" in a dev UI) rather than a fixed synthetic user.
|
|
334
234
|
*
|
|
335
235
|
* The verifier decodes the base64url cookie value and returns the embedded session.
|
|
@@ -342,55 +242,16 @@ export declare function createDevLoginHandler(options?: DevLoginHandlerOptions):
|
|
|
342
242
|
* const verifySession = createDevSessionVerifier({ role: 'owner' })
|
|
343
243
|
*
|
|
344
244
|
* // Option B: Role-switching dev login UI
|
|
345
|
-
*
|
|
245
|
+
* const loginHandler = createRequestDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] })
|
|
346
246
|
* const verifySession = createDevCookieVerifier()
|
|
347
247
|
* ```
|
|
348
248
|
*
|
|
349
|
-
* @param cookieName - Must match the `cookieName` passed to `
|
|
350
|
-
* @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`.
|
|
351
251
|
*/
|
|
352
252
|
export declare function createDevCookieVerifier(cookieName?: string): SessionVerifier;
|
|
353
253
|
/**
|
|
354
|
-
* Creates a
|
|
355
|
-
*
|
|
356
|
-
* Venue visitors can browse and initiate bookings without creating an account.
|
|
357
|
-
* This handler mounts at e.g. `/api/guest/session` and issues a session cookie
|
|
358
|
-
* with `platformRole: 'guest'` and a unique guest ID on each call (if no valid
|
|
359
|
-
* guest session already exists).
|
|
360
|
-
*
|
|
361
|
-
* The guest session cookie can be verified using `createGuestCookieVerifier`,
|
|
362
|
-
* which returns a `SessionVerifier` compatible with `createAuthMiddleware`.
|
|
363
|
-
*
|
|
364
|
-
* @param options - Cookie name, max-age, and optional `onGuestCreated` callback.
|
|
365
|
-
* @returns A Hono-compatible request handler.
|
|
366
|
-
*
|
|
367
|
-
* @deprecated Use `createRequestGuestSessionHandler` from `request-middleware.ts` instead.
|
|
368
|
-
* The Hono-specific handler will be removed in a future major version.
|
|
369
|
-
*
|
|
370
|
-
* @example
|
|
371
|
-
* ```typescript
|
|
372
|
-
* import { createGuestSessionHandler, createGuestCookieVerifier, createAuthMiddleware } from '@soulcraft/sdk/server'
|
|
373
|
-
*
|
|
374
|
-
* // Issue guest sessions
|
|
375
|
-
* app.post('/api/guest/session', createGuestSessionHandler({
|
|
376
|
-
* onGuestCreated: async (guestId) => {
|
|
377
|
-
* await db.guests.insert({ id: guestId, createdAt: new Date() })
|
|
378
|
-
* },
|
|
379
|
-
* }))
|
|
380
|
-
*
|
|
381
|
-
* // Verify guest sessions in optional auth (guests can browse)
|
|
382
|
-
* const verifyGuest = createGuestCookieVerifier()
|
|
383
|
-
* const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
384
|
-
*
|
|
385
|
-
* // Compose: check real session first, fall back to guest
|
|
386
|
-
* const { optionalAuth } = createAuthMiddleware(async (cookie) =>
|
|
387
|
-
* await verifySession(cookie) ?? await verifyGuest(cookie)
|
|
388
|
-
* )
|
|
389
|
-
* ```
|
|
390
|
-
*/
|
|
391
|
-
export declare function createGuestSessionHandler(options?: GuestSessionHandlerOptions): (c: HonoContext) => Promise<Response>;
|
|
392
|
-
/**
|
|
393
|
-
* Creates a session verifier that reads the cookie issued by `createGuestSessionHandler`.
|
|
254
|
+
* Creates a session verifier that reads the cookie issued by `createRequestGuestSessionHandler`.
|
|
394
255
|
*
|
|
395
256
|
* Returns the guest `SoulcraftSession` or `null` if no valid guest cookie is present.
|
|
396
257
|
* Compose with `createRemoteSessionVerifier` to allow both authenticated and guest access:
|
|
@@ -399,14 +260,13 @@ export declare function createGuestSessionHandler(options?: GuestSessionHandlerO
|
|
|
399
260
|
* const verifyReal = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
|
|
400
261
|
* const verifyGuest = createGuestCookieVerifier()
|
|
401
262
|
*
|
|
402
|
-
* const { optionalAuth } =
|
|
263
|
+
* const { optionalAuth } = createRequestAuthMiddleware(async (cookie) =>
|
|
403
264
|
* await verifyReal(cookie) ?? await verifyGuest(cookie)
|
|
404
265
|
* )
|
|
405
266
|
* ```
|
|
406
267
|
*
|
|
407
|
-
* @param cookieName - Must match the `cookieName` passed to `
|
|
408
|
-
* @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`.
|
|
409
270
|
*/
|
|
410
271
|
export declare function createGuestCookieVerifier(cookieName?: string): SessionVerifier;
|
|
411
|
-
export {};
|
|
412
272
|
//# sourceMappingURL=middleware.d.ts.map
|