@culturefy/shared 1.0.38 → 1.0.40

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 (81) hide show
  1. package/build/cjs/constants/app.js +45 -0
  2. package/build/cjs/constants/app.js.map +1 -0
  3. package/build/cjs/constants/index.js +10 -0
  4. package/build/cjs/constants/index.js.map +1 -0
  5. package/build/cjs/index.js +6 -0
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/middlewares/sample middleware.js +2 -0
  8. package/build/cjs/middlewares/sample middleware.js.map +1 -0
  9. package/build/cjs/middlewares/verify-middleware.js +202 -0
  10. package/build/cjs/middlewares/verify-middleware.js.map +1 -0
  11. package/build/cjs/types/app.js +2 -0
  12. package/build/cjs/types/app.js.map +1 -0
  13. package/build/cjs/types/middleware.js +2 -0
  14. package/build/cjs/types/middleware.js.map +1 -0
  15. package/build/cjs/utils/cookies.js +28 -0
  16. package/build/cjs/utils/cookies.js.map +1 -0
  17. package/build/cjs/utils/index.js +6 -0
  18. package/build/cjs/utils/index.js.map +1 -1
  19. package/build/cjs/utils/middleware.js +71 -0
  20. package/build/cjs/utils/middleware.js.map +1 -0
  21. package/build/esm/constants/app.js +41 -0
  22. package/build/esm/constants/app.js.map +1 -0
  23. package/build/esm/constants/index.js +2 -0
  24. package/build/esm/constants/index.js.map +1 -0
  25. package/build/esm/index.js +1 -0
  26. package/build/esm/index.js.map +1 -1
  27. package/build/esm/middlewares/sample middleware.js +2 -0
  28. package/build/esm/middlewares/sample middleware.js.map +1 -0
  29. package/build/esm/middlewares/verify-middleware.js +197 -0
  30. package/build/esm/middlewares/verify-middleware.js.map +1 -0
  31. package/build/esm/types/app.js +2 -0
  32. package/build/esm/types/app.js.map +1 -0
  33. package/build/esm/types/middleware.js +2 -0
  34. package/build/esm/types/middleware.js.map +1 -0
  35. package/build/esm/utils/cookies.js +24 -0
  36. package/build/esm/utils/cookies.js.map +1 -0
  37. package/build/esm/utils/index.js +1 -0
  38. package/build/esm/utils/index.js.map +1 -1
  39. package/build/esm/utils/middleware.js +65 -0
  40. package/build/esm/utils/middleware.js.map +1 -0
  41. package/build/src/constants/app.d.ts +2 -0
  42. package/build/src/constants/app.js +38 -0
  43. package/build/src/constants/app.js.map +1 -0
  44. package/build/src/constants/index.d.ts +1 -0
  45. package/build/src/constants/index.js +5 -0
  46. package/build/src/constants/index.js.map +1 -0
  47. package/build/src/index.d.ts +1 -0
  48. package/build/src/index.js +1 -0
  49. package/build/src/index.js.map +1 -1
  50. package/build/src/middlewares/sample middleware.d.ts +0 -0
  51. package/build/src/middlewares/sample middleware.js +2 -0
  52. package/build/src/middlewares/sample middleware.js.map +1 -0
  53. package/build/src/middlewares/verify-middleware.d.ts +2 -0
  54. package/build/src/middlewares/verify-middleware.js +167 -0
  55. package/build/src/middlewares/verify-middleware.js.map +1 -0
  56. package/build/src/types/app.d.ts +29 -0
  57. package/build/src/types/app.js +3 -0
  58. package/build/src/types/app.js.map +1 -0
  59. package/build/src/types/middleware.d.ts +3 -0
  60. package/build/src/types/middleware.js +3 -0
  61. package/build/src/types/middleware.js.map +1 -0
  62. package/build/src/utils/cookies.d.ts +2 -0
  63. package/build/src/utils/cookies.js +25 -0
  64. package/build/src/utils/cookies.js.map +1 -0
  65. package/build/src/utils/index.d.ts +1 -0
  66. package/build/src/utils/index.js +1 -0
  67. package/build/src/utils/index.js.map +1 -1
  68. package/build/src/utils/middleware.d.ts +12 -0
  69. package/build/src/utils/middleware.js +64 -0
  70. package/build/src/utils/middleware.js.map +1 -0
  71. package/package.json +1 -1
  72. package/src/constants/app.ts +40 -0
  73. package/src/constants/index.ts +1 -0
  74. package/src/index.ts +2 -1
  75. package/src/middlewares/sample middleware.ts +0 -0
  76. package/src/middlewares/verify-middleware.ts +197 -0
  77. package/src/types/app.ts +27 -0
  78. package/src/types/middleware.ts +10 -0
  79. package/src/utils/cookies.ts +24 -0
  80. package/src/utils/index.ts +2 -1
  81. package/src/utils/middleware.ts +70 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-middleware.js","sourceRoot":"","sources":["../../../src/middlewares/verify-middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export type IAppId = "3238hxa2";
2
+ export interface IDomainMappings {
3
+ domains: Record<string, string[]>;
4
+ clientId: string;
5
+ appId: string;
6
+ name: string;
7
+ exclude: Record<string, string[]>;
8
+ cookie: {
9
+ prefix: string;
10
+ domain: {
11
+ local: string | null;
12
+ dev: string;
13
+ staging: string;
14
+ prod: string;
15
+ };
16
+ path: string;
17
+ sameSite: string;
18
+ secure: boolean;
19
+ httpOnly: boolean;
20
+ maxAgeSec: {
21
+ sid: number;
22
+ rt: number;
23
+ };
24
+ };
25
+ auth?: {
26
+ realm: string;
27
+ clientId: string;
28
+ };
29
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/types/app.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
2
+ export type IMiddleware = (req: HttpRequest, ctx: InvocationContext, next: () => Promise<HttpResponseInit>) => Promise<HttpResponseInit>;
3
+ export type IHandler = (req: HttpRequest, ctx: InvocationContext) => Promise<HttpResponseInit>;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/types/middleware.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import { InvocationContext } from "@azure/functions";
2
+ export declare function setCookieKV(ctx: InvocationContext, key: string, value: string): void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setCookieKV = setCookieKV;
4
+ function setCookieKV(ctx, key, value) {
5
+ var _a, _b;
6
+ var _c, _d;
7
+ // Object-cookie bag (preferred)
8
+ const CTX_COOKIES_OBJ = Symbol.for("cfy.resCookies.obj");
9
+ // @ts-ignore
10
+ const objBag = ((_a = (_c = ctx)[CTX_COOKIES_OBJ]) !== null && _a !== void 0 ? _a : (_c[CTX_COOKIES_OBJ] = []));
11
+ objBag.push({
12
+ name: key,
13
+ value,
14
+ path: "/",
15
+ httpOnly: true,
16
+ secure: true, // drop to false if testing on http://
17
+ sameSite: "None", // use "Lax" for same-site
18
+ maxAge: 300, // seconds
19
+ });
20
+ // (Optional) Keep your string fallback too:
21
+ const CTX_COOKIES = Symbol.for("cfy.resCookies");
22
+ const strBag = ((_b = (_d = ctx)[CTX_COOKIES]) !== null && _b !== void 0 ? _b : (_d[CTX_COOKIES] = []));
23
+ strBag.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=300`);
24
+ }
25
+ //# sourceMappingURL=cookies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../../src/utils/cookies.ts"],"names":[],"mappings":";;AAEA,kCAqBC;AArBD,SAAgB,WAAW,CAAC,GAAsB,EAAE,GAAW,EAAE,KAAa;;;IAC5E,gCAAgC;IAChC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACzD,aAAa;IACb,MAAM,MAAM,GAAG,aAAE,GAAW,EAAC,eAAe,wCAAf,eAAe,IAAM,EAAkB,EAAC,CAAC;IACtE,MAAM,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,GAAG;QACT,KAAK;QACL,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI,EAAQ,sCAAsC;QAC1D,QAAQ,EAAE,MAAM,EAAI,0BAA0B;QAC9C,MAAM,EAAE,GAAG,EAAS,UAAU;KACjC,CAAC,CAAC;IAEH,4CAA4C;IAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,aAAE,GAAW,EAAC,WAAW,wCAAX,WAAW,IAAM,EAAc,EAAC,CAAC;IAC9D,MAAM,CAAC,IAAI,CACP,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,wDAAwD,CAClH,CAAC;AACJ,CAAC"}
@@ -3,3 +3,4 @@ export * from './response';
3
3
  export * from './initializers';
4
4
  export * from './mapper';
5
5
  export * from './jwt';
6
+ export * from './middleware';
@@ -6,4 +6,5 @@ tslib_1.__exportStar(require("./response"), exports);
6
6
  tslib_1.__exportStar(require("./initializers"), exports);
7
7
  tslib_1.__exportStar(require("./mapper"), exports);
8
8
  tslib_1.__exportStar(require("./jwt"), exports);
9
+ tslib_1.__exportStar(require("./middleware"), exports);
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":";;;AAAA,oDAA0B;AAC1B,qDAA2B;AAC3B,yDAA+B;AAC/B,mDAAyB;AACzB,gDAAsB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":";;;AAAA,oDAA0B;AAC1B,qDAA2B;AAC3B,yDAA+B;AAC/B,mDAAyB;AACzB,gDAAsB;AACtB,uDAA6B"}
@@ -0,0 +1,12 @@
1
+ import { HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
2
+ import { IHandler, IMiddleware } from "../types/middleware";
3
+ /**
4
+ * Compose Azure Functions middlewares (Koa-style).
5
+ * Each middleware gets (req, ctx, next) and must either:
6
+ * - `return await next()` to pass-through, or
7
+ * - `return <HttpResponseInit>` to short-circuit.
8
+ *
9
+ * Any headers/cookies accumulated on ctx via Symbol.for("cfy.resHeaders"/"cfy.resCookies")
10
+ * are merged into the final response.
11
+ */
12
+ export declare function withMW(middlewares: IMiddleware[], handler: IHandler): (req: HttpRequest, ctx: InvocationContext) => Promise<HttpResponseInit>;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withMW = withMW;
4
+ const tslib_1 = require("tslib");
5
+ /**
6
+ * Compose Azure Functions middlewares (Koa-style).
7
+ * Each middleware gets (req, ctx, next) and must either:
8
+ * - `return await next()` to pass-through, or
9
+ * - `return <HttpResponseInit>` to short-circuit.
10
+ *
11
+ * Any headers/cookies accumulated on ctx via Symbol.for("cfy.resHeaders"/"cfy.resCookies")
12
+ * are merged into the final response.
13
+ */
14
+ // ---- withMW (kept small; merges any ctx headers/cookies if you use them) ----
15
+ function withMW(middlewares, handler) {
16
+ return (req, ctx) => tslib_1.__awaiter(this, void 0, void 0, function* () {
17
+ var _a, _b, _c;
18
+ const stack = [...middlewares, (r, c) => tslib_1.__awaiter(this, void 0, void 0, function* () { return handler(r, c); })];
19
+ let index = -1;
20
+ const dispatch = (i) => tslib_1.__awaiter(this, void 0, void 0, function* () {
21
+ if (i <= index)
22
+ throw new Error("next() called multiple times");
23
+ index = i;
24
+ const fn = stack[i];
25
+ if (!fn)
26
+ throw new Error("No handler in middleware stack");
27
+ // next always returns a HttpResponseInit
28
+ const next = () => dispatch(i + 1);
29
+ const result = yield fn(req, ctx, next);
30
+ if (result === undefined) {
31
+ throw new Error("Middleware must return a response or `return await next()`");
32
+ }
33
+ return result;
34
+ });
35
+ const res = yield dispatch(0);
36
+ // optional: merge bags if you set them elsewhere
37
+ const CTX_HEADERS = Symbol.for("cfy.resHeaders");
38
+ const CTX_COOKIES = Symbol.for("cfy.resCookies"); // string[]
39
+ const CTX_COOKIES_OBJ = Symbol.for("cfy.resCookies.obj"); // HttpCookie[]
40
+ const merged = Object.assign(Object.assign({}, res), { headers: Object.assign({}, ((_a = res.headers) !== null && _a !== void 0 ? _a : {})) });
41
+ // merge cookies as objects (preferred by Azure Functions)
42
+ // @ts-ignore
43
+ const objCookies = ctx[CTX_COOKIES_OBJ];
44
+ if (objCookies === null || objCookies === void 0 ? void 0 : objCookies.length) {
45
+ merged.cookies = [...((_b = res.cookies) !== null && _b !== void 0 ? _b : []), ...objCookies];
46
+ }
47
+ // (optional) header fallback for environments that expect Set-Cookie header(s)
48
+ const cookies = ctx[CTX_COOKIES];
49
+ if (cookies === null || cookies === void 0 ? void 0 : cookies.length) {
50
+ const h = merged.headers;
51
+ const existing = (_c = h["Set-Cookie"]) !== null && _c !== void 0 ? _c : h["set-cookie"];
52
+ h["Set-Cookie"] = existing
53
+ ? (Array.isArray(existing) ? existing.concat(cookies) : [existing, ...cookies])
54
+ : cookies;
55
+ }
56
+ // merge extra headers if you use that bag
57
+ const extra = ctx[CTX_HEADERS];
58
+ if (extra)
59
+ for (const [k, v] of Object.entries(extra))
60
+ merged.headers[k] = v;
61
+ return merged;
62
+ });
63
+ }
64
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/utils/middleware.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@culturefy/shared",
3
3
  "description": "Shared utilities for culturefy serverless services",
4
- "version": "1.0.38",
4
+ "version": "1.0.40",
5
5
  "main": "build/cjs/index.js",
6
6
  "module": "build/esm/index.js",
7
7
  "types": "build/src/index.d.ts",
@@ -0,0 +1,40 @@
1
+ import { IAppId, IDomainMappings } from "../types/app";
2
+
3
+ export const APP_MAP: Record<IAppId, IDomainMappings> = {
4
+ '3238hxa2': {
5
+ appId: "3238hxa2",
6
+ name: "superadmin",
7
+ clientId: "cfy-superadmin-web",
8
+ domains: {
9
+ local: ["localhost:5173", "127.0.0.1:5173"],
10
+ dev: ["accounts.dev.culturefy.app"],
11
+ staging: ["accounts.staging.culturefy.app"],
12
+ prod: ["accounts.culturefy.app"]
13
+ },
14
+
15
+ auth: {
16
+ realm: "superadmin",
17
+ clientId: "cfy-superadmin-web",
18
+ },
19
+
20
+ exclude: {
21
+ prod: [] // e.g. add "app.culturefy.app" to prevent misrouting
22
+ },
23
+ cookie: {
24
+ prefix: "__Secure-auth",
25
+ domain: {
26
+ local: null, // host-bound in local
27
+ dev: ".culturefy.dev", // adjust to your dev root
28
+ staging: ".culturefy.staging", // adjust to your staging root
29
+ prod: ".culturefy.app"
30
+ },
31
+ path: "/",
32
+ sameSite: "None",
33
+ secure: true,
34
+ httpOnly: true,
35
+ maxAgeSec: { sid: 15 * 60, rt: 30 * 24 * 60 * 60 } // 15m / 30d
36
+ }
37
+
38
+ },
39
+
40
+ };
@@ -0,0 +1 @@
1
+ export * from './app';
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './types';
2
2
  export * from './enums';
3
3
  export * from './utils';
4
- export * from './middlewares';
4
+ export * from './middlewares';
5
+ export * from './constants';
File without changes
@@ -0,0 +1,197 @@
1
+ import { HttpResponseInit } from "@azure/functions";
2
+ import { HttpRequest } from "@azure/functions";
3
+ import { InvocationContext } from "@azure/functions";
4
+ import { sendResponse } from "../utils";
5
+ import { IMiddleware } from "../types/middleware";
6
+ import { IAppId } from "../types/app";
7
+ import { APP_MAP } from "../constants";
8
+ import { jwtDecode } from "jwt-decode";
9
+ import { setCookieKV } from "../utils/cookies";
10
+
11
+ const apiURL = process.env.REFRESH_SESSION_URL || ''
12
+
13
+ const parseCookieHeader = (header: string | null | undefined) => {
14
+ const out: Record<string, string> = {};
15
+ if (!header) return out;
16
+ for (const part of header.split(";")) {
17
+ const [k, ...rest] = part.trim().split("=");
18
+ if (!k) continue;
19
+ out[k] = decodeURIComponent(rest.join("=") || "");
20
+ }
21
+ return out;
22
+ };
23
+
24
+ export const verifyMw: IMiddleware = async (
25
+ req: HttpRequest,
26
+ ctx: InvocationContext,
27
+ next: () => Promise<HttpResponseInit>
28
+ ): Promise<HttpResponseInit> => {
29
+ const appId = req.headers.get("app-id") as IAppId | undefined;
30
+
31
+ if (!appId || !APP_MAP?.[appId]?.clientId) {
32
+ return sendResponse(400, { status: "bad_request", reason: "invalid_app" });
33
+ }
34
+
35
+ const expectedClientId = APP_MAP[appId].clientId;
36
+
37
+ // cookies
38
+ const cookies = parseCookieHeader(req.headers.get("cookie"));
39
+ const at = cookies[`__Secure-session-v1.${appId}.at`];
40
+ const rt = cookies[`__Secure-session-v1.${appId}.rt`];
41
+
42
+ if (!at && !rt) {
43
+ return sendResponse(401, { status: "unauthenticated", reason: "no_tokens" });
44
+ }
45
+
46
+ // decode/verify (lightweight; replace with your verifyJsonWebToken if you have it)
47
+ let p: any;
48
+ try {
49
+ p = jwtDecode(at);
50
+ } catch {
51
+ return sendResponse(401, { status: "unauthenticated", reason: "invalid_token" });
52
+ }
53
+
54
+ if (!p?.sid) {
55
+ return sendResponse(401, { status: "unauthenticated", reason: "user_not_found" });
56
+ }
57
+
58
+ const now = Math.floor(Date.now() / 1000);
59
+ // if (typeof p.exp === "number" && p.exp <= now) {
60
+ if (typeof p.exp === "number" && p.exp >= now) {
61
+ // Delegate to refresh helper; it will handle setting cookies/state or returning an error
62
+ return await getNewRefreshToken(req, ctx, appId, expectedClientId, rt, p, next);
63
+ }
64
+
65
+ // audience checks
66
+ const audOk =
67
+ (Array.isArray(p.aud) && p.aud.includes(expectedClientId)) ||
68
+ (typeof p.aud === "string" && (p.aud === expectedClientId || p.aud === "account")) ||
69
+ p.azp === expectedClientId;
70
+
71
+ if (!audOk) {
72
+ return sendResponse(403, { status: "forbidden", reason: "audience_mismatch" });
73
+ }
74
+
75
+
76
+ setCookieKV(ctx, 'ew','rre');
77
+
78
+ // pass data downstream
79
+ (ctx as any).state ??= {};
80
+ const tenantId = p.cfy_tid ?? (p.iss ? new URL(p.iss).pathname.split("/").pop() : null);
81
+
82
+ (ctx as any).state.auth = {
83
+ appId,
84
+ userId: p.sub ?? null,
85
+ businessId: p.cfy_bid ?? tenantId ?? null,
86
+ tenantId,
87
+ email: p.email ?? p.preferred_username ?? null,
88
+ name: p.name ?? undefined,
89
+ roles: p.resource_access?.[expectedClientId]?.roles ?? p.realm_access?.roles ?? [],
90
+ exp: p.exp,
91
+ };
92
+
93
+ return next();
94
+ };
95
+
96
+
97
+
98
+ async function getNewRefreshToken(
99
+ req: HttpRequest,
100
+ ctx: InvocationContext,
101
+ appId: IAppId,
102
+ expectedClientId: string,
103
+ rt: string | undefined,
104
+ p: any,
105
+ next: () => Promise<HttpResponseInit>
106
+ ): Promise<HttpResponseInit> {
107
+ // Attempt server-side refresh using RT
108
+ if (!rt) {
109
+ return sendResponse(401, { status: "unauthenticated", reason: "expired_no_rt" });
110
+ }
111
+
112
+ // Resolve realm for refresh
113
+ let realmId: string | undefined = APP_MAP[appId].auth?.realm;
114
+ if (!realmId) {
115
+ try {
116
+ const issRealm = p?.iss ? new URL(p.iss).pathname.split("/").pop() : undefined;
117
+ realmId = (p as any)?.cfy_tid || issRealm || undefined;
118
+ } catch {
119
+ realmId = undefined;
120
+ }
121
+ }
122
+
123
+ if (!realmId) {
124
+ return sendResponse(401, { status: "unauthenticated", reason: "cannot_resolve_realm" });
125
+ }
126
+
127
+ ctx.info("refreshing token payload ----------------------", {
128
+ realmId,
129
+ expectedClientId,
130
+ rt
131
+ });
132
+
133
+
134
+ // Call auth service to refresh
135
+ try {
136
+ const resp = await fetch(apiURL, {
137
+ method: "POST",
138
+ headers: { "Content-Type": "application/json" },
139
+ body: JSON.stringify({
140
+ realmId,
141
+ clientId: expectedClientId,
142
+ refresh_token: rt
143
+ })
144
+ });
145
+
146
+ if (!resp.ok) {
147
+ const text = await resp.text();
148
+ ctx.warn?.(`refresh call failed: ${resp.status} ${text}`);
149
+ return sendResponse(401, { status: "unauthenticated", reason: "refresh_failed" });
150
+ }
151
+
152
+
153
+ const payload = await resp.json();
154
+ const data = payload?.data || {};
155
+ const newAT = data.access_token as string | undefined;
156
+ const newRT = data.refresh_token as string | undefined;
157
+ if (!newAT || !newRT) {
158
+ return sendResponse(401, { status: "unauthenticated", reason: "invalid_refresh_response" });
159
+ }
160
+
161
+ // Set refreshed cookies for client session
162
+ setCookieKV(ctx, `__Secure-session-v1.${appId}.at`, newAT);
163
+ setCookieKV(ctx, `__Secure-session-v1.${appId}.rt`, newRT);
164
+
165
+ // Decode new AT and proceed
166
+ let p2: any;
167
+ try { p2 = jwtDecode(newAT); } catch { return sendResponse(401, { status: "unauthenticated", reason: "invalid_new_token" }); }
168
+
169
+ const audOk2 =
170
+ (Array.isArray(p2.aud) && p2.aud.includes(expectedClientId)) ||
171
+ (typeof p2.aud === "string" && (p2.aud === expectedClientId || p2.aud === "account")) ||
172
+ p2.azp === expectedClientId;
173
+ if (!audOk2) {
174
+ return sendResponse(403, { status: "forbidden", reason: "audience_mismatch" });
175
+ }
176
+
177
+ // Update downstream auth state with refreshed token
178
+ (ctx as any).state ??= {};
179
+ const tenantId2 = p2.cfy_tid ?? (p2.iss ? new URL(p2.iss).pathname.split("/").pop() : null);
180
+ (ctx as any).state.auth = {
181
+ appId,
182
+ userId: p2.sub ?? null,
183
+ businessId: p2.cfy_bid ?? tenantId2 ?? null,
184
+ tenantId: tenantId2,
185
+ email: p2.email ?? p2.preferred_username ?? null,
186
+ name: p2.name ?? undefined,
187
+ roles: p2.resource_access?.[expectedClientId]?.roles ?? p2.realm_access?.roles ?? [],
188
+ exp: p2.exp,
189
+ };
190
+
191
+ // Continue pipeline after refresh
192
+ return next();
193
+ } catch (e) {
194
+ ctx.error?.("refresh exception", e as any);
195
+ return sendResponse(401, { status: "unauthenticated", reason: "refresh_exception" });
196
+ }
197
+ }
@@ -0,0 +1,27 @@
1
+ export type IAppId = "3238hxa2";
2
+
3
+ export interface IDomainMappings {
4
+ domains: Record<string, string[]>;
5
+ clientId: string;
6
+ appId: string;
7
+ name: string;
8
+ exclude: Record<string, string[]>;
9
+ cookie: {
10
+ prefix: string;
11
+ domain: {
12
+ local: string | null;
13
+ dev: string;
14
+ staging: string;
15
+ prod: string;
16
+ };
17
+ path: string;
18
+ sameSite: string;
19
+ secure: boolean;
20
+ httpOnly: boolean;
21
+ maxAgeSec: { sid: number; rt: number };
22
+ };
23
+ auth?: {
24
+ realm: string;
25
+ clientId: string;
26
+ };
27
+ }
@@ -0,0 +1,10 @@
1
+ import { HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
2
+
3
+
4
+ export type IMiddleware = (
5
+ req: HttpRequest,
6
+ ctx: InvocationContext,
7
+ next: () => Promise<HttpResponseInit>
8
+ ) => Promise<HttpResponseInit>;
9
+
10
+ export type IHandler = (req: HttpRequest, ctx: InvocationContext) => Promise<HttpResponseInit>;
@@ -0,0 +1,24 @@
1
+ import { InvocationContext } from "@azure/functions";
2
+
3
+ export function setCookieKV(ctx: InvocationContext, key: string, value: string): void {
4
+ // Object-cookie bag (preferred)
5
+ const CTX_COOKIES_OBJ = Symbol.for("cfy.resCookies.obj");
6
+ // @ts-ignore
7
+ const objBag = ((ctx as any)[CTX_COOKIES_OBJ] ??= [] as HttpCookie[]);
8
+ objBag.push({
9
+ name: key,
10
+ value,
11
+ path: "/",
12
+ httpOnly: true,
13
+ secure: true, // drop to false if testing on http://
14
+ sameSite: "None", // use "Lax" for same-site
15
+ maxAge: 300, // seconds
16
+ });
17
+
18
+ // (Optional) Keep your string fallback too:
19
+ const CTX_COOKIES = Symbol.for("cfy.resCookies");
20
+ const strBag = ((ctx as any)[CTX_COOKIES] ??= [] as string[]);
21
+ strBag.push(
22
+ `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=300`
23
+ );
24
+ }
@@ -2,4 +2,5 @@ export * from './secrets';
2
2
  export * from './response';
3
3
  export * from './initializers';
4
4
  export * from './mapper';
5
- export * from './jwt';
5
+ export * from './jwt';
6
+ export * from './middleware';
@@ -0,0 +1,70 @@
1
+ import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
2
+ import { IHandler, IMiddleware } from "../types/middleware";
3
+
4
+ /**
5
+ * Compose Azure Functions middlewares (Koa-style).
6
+ * Each middleware gets (req, ctx, next) and must either:
7
+ * - `return await next()` to pass-through, or
8
+ * - `return <HttpResponseInit>` to short-circuit.
9
+ *
10
+ * Any headers/cookies accumulated on ctx via Symbol.for("cfy.resHeaders"/"cfy.resCookies")
11
+ * are merged into the final response.
12
+ */
13
+ // ---- withMW (kept small; merges any ctx headers/cookies if you use them) ----
14
+ export function withMW(middlewares: IMiddleware[], handler: IHandler) {
15
+ return async (req: HttpRequest, ctx: InvocationContext): Promise<HttpResponseInit> => {
16
+ const stack: IMiddleware[] = [...middlewares, async (r, c) => handler(r, c)];
17
+
18
+ let index = -1;
19
+ const dispatch = async (i: number): Promise<HttpResponseInit> => {
20
+ if (i <= index) throw new Error("next() called multiple times");
21
+ index = i;
22
+
23
+ const fn = stack[i];
24
+ if (!fn) throw new Error("No handler in middleware stack");
25
+
26
+ // next always returns a HttpResponseInit
27
+ const next = () => dispatch(i + 1);
28
+ const result = await fn(req, ctx, next);
29
+
30
+ if (result === undefined) {
31
+ throw new Error("Middleware must return a response or `return await next()`");
32
+ }
33
+ return result;
34
+ };
35
+
36
+ const res = await dispatch(0);
37
+
38
+ // optional: merge bags if you set them elsewhere
39
+ const CTX_HEADERS = Symbol.for("cfy.resHeaders");
40
+ const CTX_COOKIES = Symbol.for("cfy.resCookies"); // string[]
41
+ const CTX_COOKIES_OBJ = Symbol.for("cfy.resCookies.obj"); // HttpCookie[]
42
+
43
+ const merged: HttpResponseInit = { ...res, headers: { ...(res.headers ?? {}) } };
44
+
45
+ // merge cookies as objects (preferred by Azure Functions)
46
+ // @ts-ignore
47
+ const objCookies = (ctx as any)[CTX_COOKIES_OBJ] as HttpCookie[] | undefined;
48
+ if (objCookies?.length) {
49
+ merged.cookies = [...(res.cookies ?? []), ...objCookies];
50
+ }
51
+
52
+ // (optional) header fallback for environments that expect Set-Cookie header(s)
53
+ const cookies = (ctx as any)[CTX_COOKIES] as string[] | undefined;
54
+ if (cookies?.length) {
55
+ const h = merged.headers as any;
56
+ const existing = h["Set-Cookie"] ?? h["set-cookie"];
57
+ h["Set-Cookie"] = existing
58
+ ? (Array.isArray(existing) ? existing.concat(cookies) : [existing, ...cookies])
59
+ : cookies;
60
+ }
61
+
62
+ // merge extra headers if you use that bag
63
+ const extra = (ctx as any)[CTX_HEADERS] as Record<string, string | string[]> | undefined;
64
+ if (extra) for (const [k, v] of Object.entries(extra)) (merged.headers as any)[k] = v;
65
+
66
+ return merged;
67
+
68
+
69
+ };
70
+ }