@danainnovations/sonance-gate 0.1.0 → 0.2.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/README.md +16 -0
- package/dist/index.cjs +30 -7
- package/dist/index.d.cts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +28 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,4 +60,20 @@ The gate serves `GET /auth/me` → `{ sub, name, email }` (a fake Dev User outsi
|
|
|
60
60
|
|
|
61
61
|
Endpoints: `/auth/signin` (optionally `?returnTo=/path`), `/auth/signout`, `/auth/me`, `/auth/callback` (Okta's redirect URI — register `https://<your-domain>/auth/callback`).
|
|
62
62
|
|
|
63
|
+
## Identity in backend code (v0.2+)
|
|
64
|
+
|
|
65
|
+
On every request the gate lets through, it injects an `x-sonance-user` request header (spoof-proof: any client-supplied value is stripped and replaced). Read it with the bundled helper — works in any route handler or server function:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { getUser } from '@danainnovations/sonance-gate'
|
|
69
|
+
|
|
70
|
+
export async function POST(req: Request) {
|
|
71
|
+
const user = getUser(req) // { sub, name, email } | null
|
|
72
|
+
if (!user) return new Response('unauthenticated', { status: 401 })
|
|
73
|
+
// ... write rows keyed by user.sub, etc.
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Outside production it returns the fake Dev User, so backend code behaves identically in local dev. On `publicPaths` routes it returns `null` unless the visitor happens to have a session.
|
|
78
|
+
|
|
63
79
|
Sign-out clears the app session and forces a fresh Okta credential prompt on the next visit (your Okta org session for other apps stays alive).
|
package/dist/index.cjs
CHANGED
|
@@ -31,7 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
DEV_USER: () => DEV_USER,
|
|
34
|
-
createGate: () => createGate
|
|
34
|
+
createGate: () => createGate,
|
|
35
|
+
getUser: () => getUser
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(index_exports);
|
|
37
38
|
var import_middleware = require("@vercel/functions/middleware");
|
|
@@ -197,7 +198,7 @@ async function handleRequest(request, opts = {}, vars = process.env, deps = {})
|
|
|
197
198
|
if (env.mode === "open") {
|
|
198
199
|
if (path === "/auth/me") return json(DEV_USER);
|
|
199
200
|
if (path === "/auth/signin" || path === "/auth/signout") return redirect("/");
|
|
200
|
-
return
|
|
201
|
+
return { user: DEV_USER };
|
|
201
202
|
}
|
|
202
203
|
if (env.mode === "misconfigured") {
|
|
203
204
|
return new Response(
|
|
@@ -278,8 +279,9 @@ async function enforce(request, path, env, opts, deps) {
|
|
|
278
279
|
const { sub, name, email } = session;
|
|
279
280
|
return json({ sub, name, email });
|
|
280
281
|
}
|
|
281
|
-
|
|
282
|
-
if (
|
|
282
|
+
const passUser = session ? { sub: session.sub, name: session.name, email: session.email } : null;
|
|
283
|
+
if (isPublic(path, opts.publicPaths)) return { user: passUser };
|
|
284
|
+
if (session) return { user: passUser };
|
|
283
285
|
if (wantsHtml(request)) {
|
|
284
286
|
return startSignin(url, url.pathname + url.search, env, deps, signedOut);
|
|
285
287
|
}
|
|
@@ -348,13 +350,34 @@ async function handleCallback(request, url, env, deps) {
|
|
|
348
350
|
}
|
|
349
351
|
|
|
350
352
|
// src/index.ts
|
|
351
|
-
|
|
353
|
+
var USER_HEADER = "x-sonance-user";
|
|
354
|
+
function createGate(opts = {}, vars, deps) {
|
|
352
355
|
return async (request) => {
|
|
353
|
-
|
|
356
|
+
const result = await handleRequest(request, opts, vars, deps);
|
|
357
|
+
if (result instanceof Response) return result;
|
|
358
|
+
const headers = new Headers(request.headers);
|
|
359
|
+
headers.delete(USER_HEADER);
|
|
360
|
+
if (result.user) {
|
|
361
|
+
headers.set(USER_HEADER, Buffer.from(JSON.stringify(result.user)).toString("base64url"));
|
|
362
|
+
}
|
|
363
|
+
return (0, import_middleware.next)({ request: { headers } });
|
|
354
364
|
};
|
|
355
365
|
}
|
|
366
|
+
function getUser(source) {
|
|
367
|
+
const headers = source instanceof Headers ? source : source.headers;
|
|
368
|
+
const raw = headers.get(USER_HEADER);
|
|
369
|
+
if (!raw) return null;
|
|
370
|
+
try {
|
|
371
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString());
|
|
372
|
+
if (typeof parsed?.sub === "string" && typeof parsed?.email === "string") return parsed;
|
|
373
|
+
return null;
|
|
374
|
+
} catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
356
378
|
// Annotate the CommonJS export names for ESM import in node:
|
|
357
379
|
0 && (module.exports = {
|
|
358
380
|
DEV_USER,
|
|
359
|
-
createGate
|
|
381
|
+
createGate,
|
|
382
|
+
getUser
|
|
360
383
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
declare const DEV_USER: {
|
|
1
|
+
import { JWTVerifyGetKey } from 'jose';
|
|
2
|
+
|
|
3
|
+
interface SessionClaims {
|
|
5
4
|
sub: string;
|
|
6
5
|
name: string;
|
|
7
6
|
email: string;
|
|
8
|
-
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface GateOptions {
|
|
10
|
+
publicPaths?: string[];
|
|
11
|
+
}
|
|
12
|
+
interface GateDeps {
|
|
13
|
+
fetchFn?: typeof fetch;
|
|
14
|
+
jwks?: JWTVerifyGetKey;
|
|
15
|
+
}
|
|
16
|
+
declare const DEV_USER: SessionClaims;
|
|
9
17
|
|
|
10
|
-
declare function createGate(opts?: GateOptions): (request: Request) => Promise<Response>;
|
|
18
|
+
declare function createGate(opts?: GateOptions, vars?: Record<string, string | undefined>, deps?: GateDeps): (request: Request) => Promise<Response>;
|
|
19
|
+
/** Read the gate-injected identity from an incoming request (server-side). */
|
|
20
|
+
declare function getUser(source: Request | Headers): SessionClaims | null;
|
|
11
21
|
|
|
12
|
-
export { DEV_USER, type GateOptions, createGate };
|
|
22
|
+
export { DEV_USER, type GateOptions, type SessionClaims, createGate, getUser };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
declare const DEV_USER: {
|
|
1
|
+
import { JWTVerifyGetKey } from 'jose';
|
|
2
|
+
|
|
3
|
+
interface SessionClaims {
|
|
5
4
|
sub: string;
|
|
6
5
|
name: string;
|
|
7
6
|
email: string;
|
|
8
|
-
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface GateOptions {
|
|
10
|
+
publicPaths?: string[];
|
|
11
|
+
}
|
|
12
|
+
interface GateDeps {
|
|
13
|
+
fetchFn?: typeof fetch;
|
|
14
|
+
jwks?: JWTVerifyGetKey;
|
|
15
|
+
}
|
|
16
|
+
declare const DEV_USER: SessionClaims;
|
|
9
17
|
|
|
10
|
-
declare function createGate(opts?: GateOptions): (request: Request) => Promise<Response>;
|
|
18
|
+
declare function createGate(opts?: GateOptions, vars?: Record<string, string | undefined>, deps?: GateDeps): (request: Request) => Promise<Response>;
|
|
19
|
+
/** Read the gate-injected identity from an incoming request (server-side). */
|
|
20
|
+
declare function getUser(source: Request | Headers): SessionClaims | null;
|
|
11
21
|
|
|
12
|
-
export { DEV_USER, type GateOptions, createGate };
|
|
22
|
+
export { DEV_USER, type GateOptions, type SessionClaims, createGate, getUser };
|
package/dist/index.js
CHANGED
|
@@ -162,7 +162,7 @@ async function handleRequest(request, opts = {}, vars = process.env, deps = {})
|
|
|
162
162
|
if (env.mode === "open") {
|
|
163
163
|
if (path === "/auth/me") return json(DEV_USER);
|
|
164
164
|
if (path === "/auth/signin" || path === "/auth/signout") return redirect("/");
|
|
165
|
-
return
|
|
165
|
+
return { user: DEV_USER };
|
|
166
166
|
}
|
|
167
167
|
if (env.mode === "misconfigured") {
|
|
168
168
|
return new Response(
|
|
@@ -243,8 +243,9 @@ async function enforce(request, path, env, opts, deps) {
|
|
|
243
243
|
const { sub, name, email } = session;
|
|
244
244
|
return json({ sub, name, email });
|
|
245
245
|
}
|
|
246
|
-
|
|
247
|
-
if (
|
|
246
|
+
const passUser = session ? { sub: session.sub, name: session.name, email: session.email } : null;
|
|
247
|
+
if (isPublic(path, opts.publicPaths)) return { user: passUser };
|
|
248
|
+
if (session) return { user: passUser };
|
|
248
249
|
if (wantsHtml(request)) {
|
|
249
250
|
return startSignin(url, url.pathname + url.search, env, deps, signedOut);
|
|
250
251
|
}
|
|
@@ -313,12 +314,33 @@ async function handleCallback(request, url, env, deps) {
|
|
|
313
314
|
}
|
|
314
315
|
|
|
315
316
|
// src/index.ts
|
|
316
|
-
|
|
317
|
+
var USER_HEADER = "x-sonance-user";
|
|
318
|
+
function createGate(opts = {}, vars, deps) {
|
|
317
319
|
return async (request) => {
|
|
318
|
-
|
|
320
|
+
const result = await handleRequest(request, opts, vars, deps);
|
|
321
|
+
if (result instanceof Response) return result;
|
|
322
|
+
const headers = new Headers(request.headers);
|
|
323
|
+
headers.delete(USER_HEADER);
|
|
324
|
+
if (result.user) {
|
|
325
|
+
headers.set(USER_HEADER, Buffer.from(JSON.stringify(result.user)).toString("base64url"));
|
|
326
|
+
}
|
|
327
|
+
return next({ request: { headers } });
|
|
319
328
|
};
|
|
320
329
|
}
|
|
330
|
+
function getUser(source) {
|
|
331
|
+
const headers = source instanceof Headers ? source : source.headers;
|
|
332
|
+
const raw = headers.get(USER_HEADER);
|
|
333
|
+
if (!raw) return null;
|
|
334
|
+
try {
|
|
335
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString());
|
|
336
|
+
if (typeof parsed?.sub === "string" && typeof parsed?.email === "string") return parsed;
|
|
337
|
+
return null;
|
|
338
|
+
} catch {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
321
342
|
export {
|
|
322
343
|
DEV_USER,
|
|
323
|
-
createGate
|
|
344
|
+
createGate,
|
|
345
|
+
getUser
|
|
324
346
|
};
|