@eminuckan/spine 0.3.1 → 0.3.3

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 (86) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/SECURITY.md +5 -15
  3. package/dist/access/index.mjs +2 -0
  4. package/dist/{access-CGrsDMwu.js → access-BHy1v5sr.mjs} +6 -8
  5. package/dist/access-BHy1v5sr.mjs.map +1 -0
  6. package/dist/api-client/index.mjs +3 -0
  7. package/dist/api-client/server.mjs +4 -0
  8. package/dist/{api-client-CgZUMukO.js → api-client-CB7XZaMg.mjs} +8 -10
  9. package/dist/api-client-CB7XZaMg.mjs.map +1 -0
  10. package/dist/auth/auth.server.d.ts +1 -0
  11. package/dist/auth/auth.server.d.ts.map +1 -1
  12. package/dist/auth/index.mjs +1 -0
  13. package/dist/auth/route-protection.server.d.ts.map +1 -1
  14. package/dist/auth/server.mjs +3 -0
  15. package/dist/{identity-C5un-xAs.js → identity/index.mjs} +24 -21
  16. package/dist/identity/index.mjs.map +1 -0
  17. package/dist/{server-Dxsww9v9.js → identity/server.mjs} +7 -8
  18. package/dist/identity/server.mjs.map +1 -0
  19. package/dist/{index.js → index.mjs} +11 -13
  20. package/dist/{logging-DviiAkLx.js → logging/index.mjs} +22 -24
  21. package/dist/logging/index.mjs.map +1 -0
  22. package/dist/{permission-service-CvGpwI0d.js → permission-service-DUyKomU3.mjs} +6 -10
  23. package/dist/permission-service-DUyKomU3.mjs.map +1 -0
  24. package/dist/permissions/index.mjs +3 -0
  25. package/dist/{permissions-_n1hIG7Q.js → permissions-C5dTP9y4.mjs} +23 -15
  26. package/dist/permissions-C5dTP9y4.mjs.map +1 -0
  27. package/dist/query-client/index.mjs +2 -0
  28. package/dist/{query-client-Bh3TyB8W.js → query-client-_xB300gc.mjs} +49 -15
  29. package/dist/query-client-_xB300gc.mjs.map +1 -0
  30. package/dist/react-router/{index.js → index.mjs} +11 -13
  31. package/dist/react-router/server.mjs +17 -0
  32. package/dist/{redis-session-storage.server-v2VcpFsQ.js → redis-session-storage.server-DGgQcJ9B.mjs} +30 -42
  33. package/dist/redis-session-storage.server-DGgQcJ9B.mjs.map +1 -0
  34. package/dist/{server-C96NMFBy.js → server-ByScGRXA.mjs} +39 -36
  35. package/dist/server-ByScGRXA.mjs.map +1 -0
  36. package/dist/{auth.server-D5oiz9aF.js → server-CqX2yCa4.mjs} +388 -119
  37. package/dist/server-CqX2yCa4.mjs.map +1 -0
  38. package/dist/server.mjs +90 -0
  39. package/dist/server.mjs.map +1 -0
  40. package/dist/signalr/index.mjs +2 -0
  41. package/dist/{signalr-k-70VHKo.js → signalr-C-TA8nEE.mjs} +11 -6
  42. package/dist/signalr-C-TA8nEE.mjs.map +1 -0
  43. package/dist/{tenant-DfLemb6n.js → tenant/index.mjs} +19 -12
  44. package/dist/tenant/index.mjs.map +1 -0
  45. package/dist/{server-Ca-3DJf2.js → tenant/server.mjs} +12 -12
  46. package/dist/tenant/server.mjs.map +1 -0
  47. package/dist/{types-BaaE6wjY.js → types-DqCXinAk.mjs} +3 -3
  48. package/dist/types-DqCXinAk.mjs.map +1 -0
  49. package/docs/codex-for-oss-application.md +4 -0
  50. package/package.json +33 -21
  51. package/dist/access/index.js +0 -4
  52. package/dist/access-CGrsDMwu.js.map +0 -1
  53. package/dist/api-client/index.js +0 -5
  54. package/dist/api-client/server.js +0 -6
  55. package/dist/api-client-CgZUMukO.js.map +0 -1
  56. package/dist/auth/index.js +0 -0
  57. package/dist/auth/server.js +0 -6
  58. package/dist/auth.server-D5oiz9aF.js.map +0 -1
  59. package/dist/auth.server-lC94lmlx.js +0 -5
  60. package/dist/identity/index.js +0 -3
  61. package/dist/identity/server.js +0 -5
  62. package/dist/identity-C5un-xAs.js.map +0 -1
  63. package/dist/logging/index.js +0 -3
  64. package/dist/logging-DviiAkLx.js.map +0 -1
  65. package/dist/permission-service-CvGpwI0d.js.map +0 -1
  66. package/dist/permissions/index.js +0 -4
  67. package/dist/permissions-_n1hIG7Q.js.map +0 -1
  68. package/dist/query-client/index.js +0 -3
  69. package/dist/query-client-Bh3TyB8W.js.map +0 -1
  70. package/dist/react-router/server.js +0 -20
  71. package/dist/redis-session-storage.server-v2VcpFsQ.js.map +0 -1
  72. package/dist/server-B6PCxc-T.js +0 -304
  73. package/dist/server-B6PCxc-T.js.map +0 -1
  74. package/dist/server-C96NMFBy.js.map +0 -1
  75. package/dist/server-Ca-3DJf2.js.map +0 -1
  76. package/dist/server-Dxsww9v9.js.map +0 -1
  77. package/dist/server-hGrElJMG.js +0 -78
  78. package/dist/server-hGrElJMG.js.map +0 -1
  79. package/dist/server.js +0 -20
  80. package/dist/signalr/index.js +0 -3
  81. package/dist/signalr-k-70VHKo.js.map +0 -1
  82. package/dist/src-B9rDUgSb.js +0 -0
  83. package/dist/tenant/index.js +0 -3
  84. package/dist/tenant/server.js +0 -5
  85. package/dist/tenant-DfLemb6n.js.map +0 -1
  86. package/dist/types-BaaE6wjY.js.map +0 -1
@@ -1,8 +1,7 @@
1
- import { logger } from "./logging-DviiAkLx.js";
2
- import { AUTH_ERROR_COOKIE_PREFIX, createAuthSession, createOAuthState, deleteOAuthState, destroyAuthSession, destroyAuthSessionsByIdentitySession, destroyAuthSessionsBySid, destroyAuthSessionsForUser, getAuthSession, getOAuthState, listAuthSessionDataForUser, updateAuthSession } from "./redis-session-storage.server-v2VcpFsQ.js";
1
+ import { logger } from "./logging/index.mjs";
2
+ import { S as updateAuthSession, a as createOAuthState, d as destroyAuthSessionsBySid, f as destroyAuthSessionsForUser, g as getOAuthState, i as createAuthSession, l as destroyAuthSessionsByIdentitySession, o as deleteOAuthState, p as getAuthSession, s as destroyAuthSession, t as AUTH_ERROR_COOKIE_PREFIX, v as listAuthSessionDataForUser } from "./redis-session-storage.server-DGgQcJ9B.mjs";
3
3
  import * as oidc from "openid-client";
4
4
  import { createRemoteJWKSet, jwtVerify } from "jose";
5
-
6
5
  //#region src/http/response.ts
7
6
  /**
8
7
  * Create a redirect response without relying on a router/framework helper.
@@ -15,10 +14,9 @@ function createRedirectResponse(location, init = {}) {
15
14
  headers
16
15
  });
17
16
  }
18
-
19
17
  //#endregion
20
18
  //#region src/auth/authorization-parameters.ts
21
- const RESERVED_AUTHORIZATION_PARAMETER_NAMES = new Set([
19
+ const RESERVED_AUTHORIZATION_PARAMETER_NAMES = /* @__PURE__ */ new Set([
22
20
  "client_id",
23
21
  "code_challenge",
24
22
  "code_challenge_method",
@@ -31,7 +29,7 @@ const RESERVED_AUTHORIZATION_PARAMETER_NAMES = new Set([
31
29
  "scope",
32
30
  "state"
33
31
  ]);
34
- const DEFAULT_EXTRA_AUTHORIZATION_PARAMETER_NAMES = new Set([
32
+ const DEFAULT_EXTRA_AUTHORIZATION_PARAMETER_NAMES = /* @__PURE__ */ new Set([
35
33
  "acr_values",
36
34
  "kc_idp_hint",
37
35
  "login_hint",
@@ -43,7 +41,7 @@ function isAllowedExtraAuthorizationParameter(key, allowedNames, allowedPrefixes
43
41
  }
44
42
  function sanitizeExtraAuthorizationParameters(params, options = {}) {
45
43
  if (!params) return {};
46
- const allowedNames = new Set([...DEFAULT_EXTRA_AUTHORIZATION_PARAMETER_NAMES, ...(options.extraAuthParamNames ?? []).map((name) => name.trim().toLowerCase()).filter(Boolean)]);
44
+ const allowedNames = /* @__PURE__ */ new Set([...DEFAULT_EXTRA_AUTHORIZATION_PARAMETER_NAMES, ...(options.extraAuthParamNames ?? []).map((name) => name.trim().toLowerCase()).filter(Boolean)]);
47
45
  const allowedPrefixes = (options.extraAuthParamPrefixes ?? []).map((prefix) => prefix.trim().toLowerCase()).filter(Boolean);
48
46
  const sanitized = {};
49
47
  for (const [key, value] of Object.entries(params)) {
@@ -72,10 +70,19 @@ function buildAuthorizationState(baseState, publicStateContext) {
72
70
  if (!normalizedContext) return baseState;
73
71
  return `${baseState}.${Buffer.from(JSON.stringify(normalizedContext), "utf8").toString("base64url")}`;
74
72
  }
75
-
76
73
  //#endregion
77
74
  //#region src/auth/auth.server.ts
78
75
  /**
76
+ * OpenID Connect Authentication Server Module
77
+ *
78
+ * Handles:
79
+ * - Login flow (PKCE)
80
+ * - Token exchange
81
+ * - Token refresh
82
+ * - Logout
83
+ * - Session management
84
+ */
85
+ /**
79
86
  * Get effective hasLandingPage setting based on config
80
87
  */
81
88
  function getEffectiveHasLandingPage(config) {
@@ -119,8 +126,7 @@ function createAuthConfig() {
119
126
  };
120
127
  }
121
128
  function parseOidcClientAuthMethod(value, fallback) {
122
- const normalized = value?.trim().toLowerCase();
123
- switch (normalized) {
129
+ switch (value?.trim().toLowerCase()) {
124
130
  case void 0:
125
131
  case "": return fallback;
126
132
  case "none": return "none";
@@ -137,8 +143,8 @@ function getAuthConfig() {
137
143
  return OIDC_CONFIG;
138
144
  }
139
145
  let authServerCache = null;
140
- const CACHE_TTL = 60 * 60 * 1e3;
141
- const jwksCache = new Map();
146
+ const CACHE_TTL = 3600 * 1e3;
147
+ const jwksCache = /* @__PURE__ */ new Map();
142
148
  function normalizeIssuer(value) {
143
149
  const normalized = value?.trim().replace(/\/+$/, "");
144
150
  return normalized && normalized.length > 0 ? normalized : null;
@@ -188,10 +194,16 @@ function appendApplicationInitiatedActionResult(returnUrl, action, status) {
188
194
  const params = new URLSearchParams();
189
195
  if (action) params.set("kc_action", action);
190
196
  if (status) params.set("kc_action_status", status);
191
- const separator = returnUrl.includes("?") ? "&" : "?";
192
- return `${returnUrl}${separator}${params.toString()}`;
197
+ return `${returnUrl}${returnUrl.includes("?") ? "&" : "?"}${params.toString()}`;
193
198
  }
194
199
  }
200
+ function createAuthorizationResponseUrl(requestUrl, redirectUri) {
201
+ const incomingUrl = new URL(requestUrl);
202
+ const authorizationResponseUrl = new URL(redirectUri);
203
+ authorizationResponseUrl.search = incomingUrl.search;
204
+ authorizationResponseUrl.hash = "";
205
+ return authorizationResponseUrl;
206
+ }
195
207
  function isAuthLoopPath(path) {
196
208
  const normalized = path.split("#")[0].split("?")[0].replace(/\/+$/, "") || "/";
197
209
  return normalized === "/auth/logout" || normalized === "/auth/callback";
@@ -215,8 +227,7 @@ function shouldAllowInsecureOidcRequests(authority) {
215
227
  return isLocalInsecureIssuer(authority);
216
228
  }
217
229
  function getDiscoveryOptions() {
218
- const config = getAuthConfig();
219
- return shouldAllowInsecureOidcRequests(config.authority) ? {
230
+ return shouldAllowInsecureOidcRequests(getAuthConfig().authority) ? {
220
231
  algorithm: "oidc",
221
232
  execute: [oidc.allowInsecureRequests]
222
233
  } : { algorithm: "oidc" };
@@ -232,7 +243,6 @@ function getClientAuthentication(config) {
232
243
  case "client_secret_post":
233
244
  if (!config.clientSecret) throw new Error("OIDC_CLIENT_SECRET is required for client_secret_post authentication");
234
245
  return oidc.ClientSecretPost(config.clientSecret);
235
- case "none":
236
246
  default: return oidc.None();
237
247
  }
238
248
  }
@@ -247,8 +257,7 @@ function shouldLogoutAfterOAuthError(error) {
247
257
  return message.includes("invalid_grant") || message.includes("invalid_token") || message.includes("unauthorized");
248
258
  }
249
259
  function getLogoutScope(url) {
250
- const requestedScope = url.searchParams.get("logout") ?? url.searchParams.get("logout_scope") ?? url.searchParams.get("scope");
251
- const normalized = requestedScope?.trim().toLowerCase();
260
+ const normalized = (url.searchParams.get("logout") ?? url.searchParams.get("logout_scope") ?? url.searchParams.get("scope"))?.trim().toLowerCase();
252
261
  if (normalized === "local" || normalized === "application" || normalized === "app" || normalized === "current-device") return "local";
253
262
  if (normalized === "all" || normalized === "all-local" || normalized === "all-devices" || normalized === "everywhere") return "all";
254
263
  if (url.searchParams.get("local_only") === "true" || url.searchParams.get("client_id_only") === "true") return "local";
@@ -332,23 +341,19 @@ function getJwks(jwksUri) {
332
341
  return jwks;
333
342
  }
334
343
  async function getLogoutTokenFromRequest(request) {
335
- const contentType = request.headers.get("content-type") ?? "";
336
- if (contentType.includes("application/json")) {
344
+ if ((request.headers.get("content-type") ?? "").includes("application/json")) {
337
345
  const body = await request.json().catch(() => null);
338
346
  return typeof body?.logout_token === "string" ? body.logout_token : null;
339
347
  }
340
- const formData = await request.formData().catch(() => null);
341
- const logoutToken = formData?.get("logout_token");
348
+ const logoutToken = (await request.formData().catch(() => null))?.get("logout_token");
342
349
  return typeof logoutToken === "string" ? logoutToken : null;
343
350
  }
344
351
  function validateBackChannelLogoutClaims(payload, clientId) {
345
352
  const events = payload.events;
346
- const hasBackChannelEvent = events && typeof events === "object" && !Array.isArray(events) && "http://schemas.openid.net/event/backchannel-logout" in events;
347
- if (!hasBackChannelEvent) throw new Error("Invalid back-channel logout token: missing back-channel logout event");
353
+ if (!(events && typeof events === "object" && !Array.isArray(events) && "http://schemas.openid.net/event/backchannel-logout" in events)) throw new Error("Invalid back-channel logout token: missing back-channel logout event");
348
354
  if ("nonce" in payload) throw new Error("Invalid back-channel logout token: nonce is not allowed");
349
355
  const audience = payload.aud;
350
- const hasClientAudience = Array.isArray(audience) ? audience.includes(clientId) : audience === clientId;
351
- if (!hasClientAudience) throw new Error("Invalid back-channel logout token: audience mismatch");
356
+ if (!(Array.isArray(audience) ? audience.includes(clientId) : audience === clientId)) throw new Error("Invalid back-channel logout token: audience mismatch");
352
357
  const subject = typeof payload.sub === "string" ? payload.sub : void 0;
353
358
  const sid = typeof payload.sid === "string" ? payload.sid : void 0;
354
359
  if (!subject && !sid) throw new Error("Invalid back-channel logout token: subject or sid is required");
@@ -430,7 +435,6 @@ function getStringClaim(claims, claimKeys) {
430
435
  return trimmed.length > 0 ? trimmed : void 0;
431
436
  }
432
437
  if (typeof value === "number" || typeof value === "boolean") return `${value}`;
433
- return void 0;
434
438
  }
435
439
  function getNumberClaim(claims, claimKeys) {
436
440
  const { value } = getFirstClaimValue(claims, claimKeys);
@@ -439,7 +443,6 @@ function getNumberClaim(claims, claimKeys) {
439
443
  const parsed = Number(value);
440
444
  return Number.isFinite(parsed) ? parsed : void 0;
441
445
  }
442
- return void 0;
443
446
  }
444
447
  function getBooleanClaim(claims, claimKeys, defaultValue = false) {
445
448
  const { value } = getFirstClaimValue(claims, claimKeys);
@@ -577,10 +580,9 @@ function getAuthError(request) {
577
580
  if (!error) return null;
578
581
  const descRegex = new RegExp(`${AUTH_ERROR_DESC_COOKIE}=([^;]+)`);
579
582
  const descMatch = cookies.match(descRegex);
580
- const description = descMatch ? decodeURIComponent(descMatch[1]) : void 0;
581
583
  return {
582
584
  error,
583
- description
585
+ description: descMatch ? decodeURIComponent(descMatch[1]) : void 0
584
586
  };
585
587
  }
586
588
  /**
@@ -598,8 +600,7 @@ function clearAuthErrorHeaders() {
598
600
  * Check if request has auth error (quick check without parsing)
599
601
  */
600
602
  function hasAuthError(request) {
601
- const cookies = request.headers.get("Cookie");
602
- return cookies?.includes(`${AUTH_ERROR_COOKIE}=`) ?? false;
603
+ return request.headers.get("Cookie")?.includes(`${AUTH_ERROR_COOKIE}=`) ?? false;
603
604
  }
604
605
  /**
605
606
  * Initiate OAuth login flow
@@ -611,15 +612,12 @@ async function login(request, returnUrlOrOptions) {
611
612
  try {
612
613
  const config = getAuthConfig();
613
614
  const options = typeof returnUrlOrOptions === "string" ? { returnUrl: returnUrlOrOptions } : returnUrlOrOptions || {};
614
- const cookies = request.headers.get("Cookie");
615
- const hasError = cookies?.includes(`${AUTH_ERROR_COOKIE}=`);
616
- if (hasError) {
615
+ if (request.headers.get("Cookie")?.includes(`${AUTH_ERROR_COOKIE}=`)) {
617
616
  logger.warn("Auth error cookie detected, preventing redirect loop");
618
- const headers$1 = new Headers();
619
- headers$1.append("Set-Cookie", `${AUTH_ERROR_COOKIE}=; Path=/; Max-Age=0`);
620
- const redirectUri = new URL(config.redirectUri);
621
- const baseUrl = redirectUri.origin;
622
- return createRedirectResponse(baseUrl, { headers: headers$1 });
617
+ const headers = new Headers();
618
+ headers.append("Set-Cookie", `${AUTH_ERROR_COOKIE}=; Path=/; Max-Age=0`);
619
+ const baseUrl = new URL(config.redirectUri).origin;
620
+ return createRedirectResponse(baseUrl, { headers });
623
621
  }
624
622
  const oidcConfig = await getOAuthConfig();
625
623
  const codeVerifier = oidc.randomPKCECodeVerifier();
@@ -706,25 +704,24 @@ async function handleCallback(request) {
706
704
  });
707
705
  if (error) {
708
706
  if (kcActionStatus && state) {
709
- const cookies$1 = request.headers.get("Cookie");
710
- const oauthStateRegex$1 = new RegExp(`${OAUTH_STATE_COOKIE}=([^;]+)`);
711
- const cookieMatch$1 = cookies$1?.match(oauthStateRegex$1);
712
- const stateId$1 = cookieMatch$1?.[1];
713
- if (stateId$1) {
714
- const oauthState$1 = await getOAuthState(stateId$1);
715
- const stateAge$1 = oauthState$1 ? Date.now() - oauthState$1.createdAt : Number.POSITIVE_INFINITY;
716
- if (oauthState$1 && oauthState$1.state === state && stateAge$1 <= 10 * 60 * 1e3) {
717
- await deleteOAuthState(stateId$1);
718
- const headers$2 = new Headers();
719
- headers$2.append("Set-Cookie", `${OAUTH_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
720
- const redirectUrl$1 = appendApplicationInitiatedActionResult(oauthState$1.returnUrl || "/", kcAction || oauthState$1.kcAction, kcActionStatus);
707
+ const cookies = request.headers.get("Cookie");
708
+ const oauthStateRegex = new RegExp(`${OAUTH_STATE_COOKIE}=([^;]+)`);
709
+ const stateId = (cookies?.match(oauthStateRegex))?.[1];
710
+ if (stateId) {
711
+ const oauthState = await getOAuthState(stateId);
712
+ const stateAge = oauthState ? Date.now() - oauthState.createdAt : Number.POSITIVE_INFINITY;
713
+ if (oauthState && oauthState.state === state && stateAge <= 600 * 1e3) {
714
+ await deleteOAuthState(stateId);
715
+ const headers = new Headers();
716
+ headers.append("Set-Cookie", `${OAUTH_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
717
+ const redirectUrl = appendApplicationInitiatedActionResult(oauthState.returnUrl || "/", kcAction || oauthState.kcAction, kcActionStatus);
721
718
  logger.info("Application initiated action returned with OAuth error", {
722
719
  error,
723
720
  errorDescription,
724
- kcAction: kcAction || oauthState$1.kcAction,
721
+ kcAction: kcAction || oauthState.kcAction,
725
722
  kcActionStatus
726
723
  });
727
- return createRedirectResponse(redirectUrl$1, { headers: headers$2 });
724
+ return createRedirectResponse(redirectUrl, { headers });
728
725
  }
729
726
  }
730
727
  }
@@ -737,82 +734,74 @@ async function handleCallback(request) {
737
734
  });
738
735
  if (error === "access_denied") {
739
736
  logger.warn("Access denied for this application", { clientId: config.clientId });
740
- const headers$2 = await destroyAuthSession(request);
741
- headers$2.append("Set-Cookie", `${AUTH_ERROR_COOKIE}=access_denied; Path=/; HttpOnly; SameSite=Lax; Max-Age=300`);
742
- headers$2.append("Set-Cookie", `${AUTH_ERROR_DESC_COOKIE}=${encodeURIComponent(errorDescription || "You do not have access to this application.")}; Path=/; SameSite=Lax; Max-Age=300`);
743
- const redirectUri$1 = new URL(config.redirectUri);
744
- const baseUrl$1 = redirectUri$1.origin;
737
+ const headers = await destroyAuthSession(request);
738
+ headers.append("Set-Cookie", `${AUTH_ERROR_COOKIE}=access_denied; Path=/; HttpOnly; SameSite=Lax; Max-Age=300`);
739
+ headers.append("Set-Cookie", `${AUTH_ERROR_DESC_COOKIE}=${encodeURIComponent(errorDescription || "You do not have access to this application.")}; Path=/; SameSite=Lax; Max-Age=300`);
740
+ const baseUrl = new URL(config.redirectUri).origin;
745
741
  logger.info("Redirecting to /auth/login to show access_denied error", {
746
742
  hasLandingPage,
747
- baseUrl: baseUrl$1,
743
+ baseUrl,
748
744
  configRedirectUri: config.redirectUri
749
745
  });
750
- return createRedirectResponse(`${baseUrl$1}/auth/login`, { headers: headers$2 });
746
+ return createRedirectResponse(`${baseUrl}/auth/login`, { headers });
751
747
  }
752
748
  if (error === "login_required") {
753
749
  logger.info("Login required, user session may have expired");
754
- const headers$2 = await destroyAuthSession(request);
755
- const redirectUri$1 = new URL(config.redirectUri);
756
- const baseUrl$1 = redirectUri$1.origin;
757
- return createRedirectResponse(baseUrl$1, { headers: headers$2 });
750
+ const headers = await destroyAuthSession(request);
751
+ const baseUrl = new URL(config.redirectUri).origin;
752
+ return createRedirectResponse(baseUrl, { headers });
758
753
  }
759
- const headers$1 = await destroyAuthSession(request);
760
- headers$1.append("Set-Cookie", `${AUTH_ERROR_COOKIE}=${encodeURIComponent(error)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=300`);
761
- if (errorDescription) headers$1.append("Set-Cookie", `${AUTH_ERROR_DESC_COOKIE}=${encodeURIComponent(errorDescription)}; Path=/; SameSite=Lax; Max-Age=300`);
762
- const redirectUri = new URL(config.redirectUri);
763
- const baseUrl = redirectUri.origin;
764
- return createRedirectResponse(baseUrl, { headers: headers$1 });
754
+ const headers = await destroyAuthSession(request);
755
+ headers.append("Set-Cookie", `${AUTH_ERROR_COOKIE}=${encodeURIComponent(error)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=300`);
756
+ if (errorDescription) headers.append("Set-Cookie", `${AUTH_ERROR_DESC_COOKIE}=${encodeURIComponent(errorDescription)}; Path=/; SameSite=Lax; Max-Age=300`);
757
+ const baseUrl = new URL(config.redirectUri).origin;
758
+ return createRedirectResponse(baseUrl, { headers });
765
759
  }
766
760
  const cookies = request.headers.get("Cookie");
767
761
  const oauthStateRegex = new RegExp(`${OAUTH_STATE_COOKIE}=([^;]+)`);
768
- const cookieMatch = cookies?.match(oauthStateRegex);
769
- const stateId = cookieMatch?.[1];
762
+ const stateId = (cookies?.match(oauthStateRegex))?.[1];
770
763
  if (!stateId) throw new Error("OAuth state ID not found in cookie");
771
764
  const oauthState = await getOAuthState(stateId);
772
765
  if (!oauthState) throw new Error("No OAuth state found - state may have expired");
773
766
  if (!state) throw new Error("Missing required callback state parameter");
774
767
  if (oauthState.state !== state) throw new Error(`OAuth state mismatch`);
775
- const stateAge = Date.now() - oauthState.createdAt;
776
- if (stateAge > 10 * 60 * 1e3) throw new Error("OAuth state expired");
768
+ if (Date.now() - oauthState.createdAt > 600 * 1e3) throw new Error("OAuth state expired");
777
769
  if (!code) {
778
770
  if (kcActionStatus) {
779
771
  await deleteOAuthState(stateId);
780
- const headers$1 = new Headers();
781
- headers$1.append("Set-Cookie", `${OAUTH_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
782
- const redirectUrl$1 = appendApplicationInitiatedActionResult(oauthState.returnUrl || "/", kcAction || oauthState.kcAction, kcActionStatus);
772
+ const headers = new Headers();
773
+ headers.append("Set-Cookie", `${OAUTH_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
774
+ const redirectUrl = appendApplicationInitiatedActionResult(oauthState.returnUrl || "/", kcAction || oauthState.kcAction, kcActionStatus);
783
775
  logger.info("Application initiated action returned without authorization code", {
784
776
  kcAction: kcAction || oauthState.kcAction,
785
777
  kcActionStatus
786
778
  });
787
- return createRedirectResponse(redirectUrl$1, { headers: headers$1 });
779
+ return createRedirectResponse(redirectUrl, { headers });
788
780
  }
789
781
  throw new Error("Missing required callback code parameter");
790
782
  }
791
783
  logger.info("Initiating token exchange");
792
784
  const oidcConfig = await getOAuthConfig();
793
- const tokenResult = await oidc.authorizationCodeGrant(oidcConfig, url, {
785
+ const authorizationResponseUrl = createAuthorizationResponseUrl(request.url, config.redirectUri);
786
+ const tokenResult = await oidc.authorizationCodeGrant(oidcConfig, authorizationResponseUrl, {
794
787
  pkceCodeVerifier: oauthState.codeVerifier,
795
788
  expectedState: oauthState.state,
796
789
  expectedNonce: oauthState.nonce,
797
790
  idTokenExpected: config.scope.split(/\s+/).includes("openid")
798
791
  });
799
792
  logger.info("Token exchange completed successfully");
800
- const claims = getClaimsFromTokenResponse(tokenResult);
801
- const newSessionData = await createSessionData(tokenResult, claims);
802
- const sessionHeaders = await createAuthSession(request, newSessionData);
793
+ const sessionHeaders = await createAuthSession(request, await createSessionData(tokenResult, getClaimsFromTokenResponse(tokenResult)));
803
794
  await deleteOAuthState(stateId);
804
795
  const headers = new Headers(sessionHeaders);
805
796
  headers.append("Set-Cookie", `${OAUTH_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
806
797
  logger.info("OAuth callback processed successfully");
807
- const redirectUrl = appendApplicationInitiatedActionResult(oauthState.returnUrl || "/", kcAction || oauthState.kcAction, kcActionStatus);
808
- return createRedirectResponse(redirectUrl, { headers });
798
+ return createRedirectResponse(appendApplicationInitiatedActionResult(oauthState.returnUrl || "/", kcAction || oauthState.kcAction, kcActionStatus), { headers });
809
799
  } catch (error) {
810
800
  logger.error("OAuth callback failed", error instanceof Error ? error : void 0);
811
801
  try {
812
802
  const cookies = request.headers.get("Cookie");
813
803
  const oauthStateRegex = new RegExp(`${OAUTH_STATE_COOKIE}=([^;]+)`);
814
- const cookieMatch = cookies?.match(oauthStateRegex);
815
- const stateId = cookieMatch?.[1];
804
+ const stateId = (cookies?.match(oauthStateRegex))?.[1];
816
805
  if (stateId) await deleteOAuthState(stateId);
817
806
  } catch {}
818
807
  await destroyAuthSession(request);
@@ -840,23 +829,20 @@ async function logout(request) {
840
829
  const sessionData = await getAuthSession(request);
841
830
  const idToken = sessionData.idToken;
842
831
  if (logoutScope === "local") {
843
- const headers$1 = await destroyAuthSession(request);
844
- const redirectUrl = returnUrl || "/";
845
- const absoluteRedirectUrl = getAbsoluteRedirectUrl(request, redirectUrl);
846
- headers$1.append("Set-Cookie", "logout_return_url=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0");
832
+ const headers = await destroyAuthSession(request);
833
+ const absoluteRedirectUrl = getAbsoluteRedirectUrl(request, returnUrl || "/");
834
+ headers.append("Set-Cookie", "logout_return_url=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0");
847
835
  logger.info("Local application logout completed", { redirectUrl: absoluteRedirectUrl });
848
- return createRedirectResponse(absoluteRedirectUrl, { headers: headers$1 });
836
+ return createRedirectResponse(absoluteRedirectUrl, { headers });
849
837
  }
850
838
  const sessionHeaders = new Headers();
851
839
  if (logoutScope === "all" && sessionData.userId) {
852
840
  await revokeAndDestroyAllUserSessionsBestEffort(sessionData.userId);
853
841
  sessionHeaders.append("Set-Cookie", "logout_return_url=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0");
854
- const expiredHeaders = await destroyAuthSession(request);
855
- expiredHeaders.forEach((value, key) => sessionHeaders.append(key, value));
842
+ (await destroyAuthSession(request)).forEach((value, key) => sessionHeaders.append(key, value));
856
843
  } else {
857
844
  await revokeSessionTokensBestEffort(sessionData);
858
- const expiredHeaders = await destroyAuthSession(request);
859
- expiredHeaders.forEach((value, key) => sessionHeaders.append(key, value));
845
+ (await destroyAuthSession(request)).forEach((value, key) => sessionHeaders.append(key, value));
860
846
  }
861
847
  const headers = new Headers(sessionHeaders);
862
848
  if (returnUrl) headers.append("Set-Cookie", `logout_return_url=${encodeURIComponent(returnUrl)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=300`);
@@ -882,14 +868,12 @@ async function logout(request) {
882
868
  } catch (error) {
883
869
  logger.warn("OIDC end_session endpoint unavailable, falling back to local redirect", { error: getOAuthErrorMessage(error) });
884
870
  }
885
- const registeredPath = config.postLogoutRedirectUri || "/";
886
- const finalRedirectUrl = getAbsoluteRedirectUrl(request, registeredPath);
871
+ const finalRedirectUrl = getAbsoluteRedirectUrl(request, config.postLogoutRedirectUri || "/");
887
872
  logger.info("Logout completed", { redirectUrl: finalRedirectUrl });
888
873
  return createRedirectResponse(finalRedirectUrl, { headers });
889
874
  } catch (error) {
890
875
  logger.error("Logout failed", error instanceof Error ? error : void 0);
891
- const headers = await destroyAuthSession(request);
892
- return createRedirectResponse("/", { headers });
876
+ return createRedirectResponse("/", { headers: await destroyAuthSession(request) });
893
877
  }
894
878
  }
895
879
  /**
@@ -904,8 +888,7 @@ async function handleBackChannelLogout(request) {
904
888
  if (request.method !== "POST") return Response.json({ error: "method_not_allowed" }, { status: 405 });
905
889
  try {
906
890
  const config = getAuthConfig();
907
- const oidcConfig = await getOAuthConfig();
908
- const serverMetadata = oidcConfig.serverMetadata();
891
+ const serverMetadata = (await getOAuthConfig()).serverMetadata();
909
892
  const logoutToken = await getLogoutTokenFromRequest(request);
910
893
  if (!logoutToken) return Response.json({ error: "missing_logout_token" }, { status: 400 });
911
894
  if (!serverMetadata.jwks_uri) throw new Error("OIDC provider does not expose jwks_uri");
@@ -915,12 +898,11 @@ async function handleBackChannelLogout(request) {
915
898
  clockTolerance: 60
916
899
  });
917
900
  const claims = validateBackChannelLogoutClaims(payload, config.clientId);
918
- const destroyedSessions = await destroyAuthSessionsByIdentitySession({
919
- sid: claims.sid,
920
- userId: claims.subject
921
- });
922
901
  const result = {
923
- destroyedSessions,
902
+ destroyedSessions: await destroyAuthSessionsByIdentitySession({
903
+ sid: claims.sid,
904
+ userId: claims.subject
905
+ }),
924
906
  issuer: claims.issuer,
925
907
  subject: claims.subject,
926
908
  sid: claims.sid
@@ -947,16 +929,14 @@ async function handleBackChannelLogout(request) {
947
929
  async function handleFrontChannelLogout(request) {
948
930
  try {
949
931
  const config = getAuthConfig();
950
- const oidcConfig = await getOAuthConfig();
951
- const serverMetadata = oidcConfig.serverMetadata();
932
+ const serverMetadata = (await getOAuthConfig()).serverMetadata();
952
933
  const url = new URL(request.url);
953
934
  const issuer = url.searchParams.get("iss");
954
935
  const sid = url.searchParams.get("sid");
955
936
  const expectedIssuer = normalizeIssuer(serverMetadata.issuer ?? config.authority);
956
937
  if (!issuer || normalizeIssuer(issuer) !== expectedIssuer) return new Response(null, { status: 204 });
957
- const destroyedSessions = sid ? await destroyAuthSessionsBySid(sid) : 0;
958
938
  const result = {
959
- destroyedSessions,
939
+ destroyedSessions: sid ? await destroyAuthSessionsBySid(sid) : 0,
960
940
  issuer,
961
941
  sid: sid ?? void 0
962
942
  };
@@ -975,8 +955,7 @@ async function handleFrontChannelLogout(request) {
975
955
  */
976
956
  async function getUser(request) {
977
957
  try {
978
- const sessionData = await getAuthSession(request);
979
- return sessionData.user || null;
958
+ return (await getAuthSession(request)).user || null;
980
959
  } catch (error) {
981
960
  logger.error("Failed to get user", error instanceof Error ? error : void 0);
982
961
  return null;
@@ -1000,8 +979,7 @@ async function requireAuth(request) {
1000
979
  */
1001
980
  async function getAccessToken(request) {
1002
981
  try {
1003
- const sessionData = await getAuthSession(request);
1004
- return sessionData.accessToken || null;
982
+ return (await getAuthSession(request)).accessToken || null;
1005
983
  } catch (error) {
1006
984
  logger.error("Failed to get access token", error instanceof Error ? error : void 0);
1007
985
  return null;
@@ -1060,7 +1038,298 @@ function clearAuthServerCache() {
1060
1038
  authServerCache = null;
1061
1039
  jwksCache.clear();
1062
1040
  }
1063
-
1064
1041
  //#endregion
1065
- export { clearAuthErrorHeaders, clearAuthServerCache, configureAuthClaimMapping, createRedirectResponse, extractUserInfo, getAccessToken, getAuthError, getUser, handleBackChannelLogout, handleCallback, handleFrontChannelLogout, hasAuthError, login, logout, refreshTokens, requireAuth, resetAuthClaimMapping };
1066
- //# sourceMappingURL=auth.server-D5oiz9aF.js.map
1042
+ //#region src/auth/route-protection.server.ts
1043
+ /**
1044
+ * Route Protection Server Module
1045
+ *
1046
+ * Provides route protection utilities for different authentication levels.
1047
+ */
1048
+ const REFRESH_THRESHOLD = resolveRefreshThreshold();
1049
+ function resolveRefreshThreshold() {
1050
+ const configured = Number(process.env.OIDC_REFRESH_THRESHOLD_MS);
1051
+ return Number.isFinite(configured) && configured > 0 ? configured : 6e4;
1052
+ }
1053
+ /**
1054
+ * Check if token needs refresh
1055
+ */
1056
+ async function shouldRefreshToken(request) {
1057
+ try {
1058
+ const sessionData = await getAuthSession(request);
1059
+ if (!sessionData.refreshToken || sessionData.refreshToken.length === 0) {
1060
+ if (sessionData.expiresAt && Date.now() >= sessionData.expiresAt) {
1061
+ logger.info("Token expired and no refresh token, forcing local application logout");
1062
+ throw await logout(await createAutomaticLogoutRequest(request, "expired-no-refresh-token"));
1063
+ }
1064
+ return false;
1065
+ }
1066
+ if (!sessionData.expiresAt || !sessionData.accessToken) return false;
1067
+ const now = Date.now();
1068
+ let jwtExpiry = null;
1069
+ try {
1070
+ const tokenParts = sessionData.accessToken.split(".");
1071
+ if (tokenParts.length === 3) {
1072
+ const payload = JSON.parse(Buffer.from(tokenParts[1], "base64").toString());
1073
+ if (payload.exp) jwtExpiry = payload.exp * 1e3;
1074
+ }
1075
+ } catch {}
1076
+ return (jwtExpiry && jwtExpiry < sessionData.expiresAt ? jwtExpiry : sessionData.expiresAt) - now <= REFRESH_THRESHOLD;
1077
+ } catch (error) {
1078
+ logger.error("Error checking token refresh", error instanceof Error ? error : void 0);
1079
+ return false;
1080
+ }
1081
+ }
1082
+ /**
1083
+ * Auto-refresh tokens if needed
1084
+ */
1085
+ async function autoRefreshTokens(request) {
1086
+ try {
1087
+ if (await shouldRefreshToken(request)) {
1088
+ logger.info("Auto-refreshing tokens due to expiry");
1089
+ const result = await refreshTokens(request);
1090
+ if (result.success) logger.info("Auto-refresh completed successfully");
1091
+ else {
1092
+ logger.error("Auto-refresh failed", void 0, { error: result.error });
1093
+ if (result.shouldLogout) {
1094
+ logger.error("Refresh token invalid, forcing local application logout");
1095
+ throw await logout(await createAutomaticLogoutRequest(request, "refresh-failed"));
1096
+ }
1097
+ }
1098
+ }
1099
+ } catch (error) {
1100
+ if (error instanceof Response && error.status >= 300 && error.status < 400) throw error;
1101
+ throw error;
1102
+ }
1103
+ }
1104
+ let protectionConfig = {};
1105
+ /**
1106
+ * Configure route protection with identity, tenant, and app policy checkers
1107
+ */
1108
+ function configureRouteProtection(config) {
1109
+ protectionConfig = config;
1110
+ }
1111
+ /**
1112
+ * Reset route protection to its built-in defaults.
1113
+ */
1114
+ function resetRouteProtectionConfig() {
1115
+ protectionConfig = {};
1116
+ }
1117
+ function createRedirectFromConfig(redirect) {
1118
+ return createRedirectResponse(redirect.location, {
1119
+ headers: redirect.headers,
1120
+ status: redirect.status
1121
+ });
1122
+ }
1123
+ function getLoginReturnUrl(request, currentPath, protection) {
1124
+ if (protectionConfig.getLoginReturnUrl) return protectionConfig.getLoginReturnUrl({
1125
+ request,
1126
+ currentPath,
1127
+ protection
1128
+ });
1129
+ switch (protection) {
1130
+ default: {
1131
+ const url = new URL(request.url);
1132
+ return url.pathname === "/" ? "/" : `${url.pathname}${url.search}`;
1133
+ }
1134
+ }
1135
+ }
1136
+ async function createAutomaticLogoutRequest(request, reason) {
1137
+ if (protectionConfig.createAutomaticLogoutRequest) return protectionConfig.createAutomaticLogoutRequest({
1138
+ request,
1139
+ reason
1140
+ });
1141
+ const logoutUrl = new URL(request.url);
1142
+ logoutUrl.pathname = "/auth/logout";
1143
+ logoutUrl.searchParams.set("logout", "local");
1144
+ return new Request(logoutUrl.toString(), { headers: request.headers });
1145
+ }
1146
+ function createRouteResolverContext(request, user, currentPath, protection) {
1147
+ let identityContextPromise = null;
1148
+ let currentTenantPromise = null;
1149
+ let initializeTenantPromise = null;
1150
+ return {
1151
+ request,
1152
+ user,
1153
+ currentPath,
1154
+ protection,
1155
+ getIdentityContext: async (forceRefresh = false) => {
1156
+ if (!protectionConfig.identityChecker) return null;
1157
+ if (forceRefresh) return protectionConfig.identityChecker.getIdentityContext(request, user.sub, true);
1158
+ if (!identityContextPromise) identityContextPromise = protectionConfig.identityChecker.getIdentityContext(request, user.sub);
1159
+ return identityContextPromise;
1160
+ },
1161
+ getCurrentTenant: async () => {
1162
+ if (!protectionConfig.tenantChecker) return null;
1163
+ if (!currentTenantPromise) currentTenantPromise = protectionConfig.tenantChecker.getCurrentTenant(request);
1164
+ return currentTenantPromise;
1165
+ },
1166
+ initializeTenant: async () => {
1167
+ if (!protectionConfig.tenantChecker) return null;
1168
+ if (!initializeTenantPromise) initializeTenantPromise = protectionConfig.tenantChecker.initializeTenant(request);
1169
+ return initializeTenantPromise;
1170
+ }
1171
+ };
1172
+ }
1173
+ async function applyConfiguredRouteResolution(request, user, currentPath, protection) {
1174
+ if (!protectionConfig.resolveRoute) return false;
1175
+ const context = createRouteResolverContext(request, user, currentPath, protection);
1176
+ try {
1177
+ const result = await protectionConfig.resolveRoute(context);
1178
+ if (result) throw createRedirectFromConfig(result);
1179
+ return true;
1180
+ } catch (error) {
1181
+ if (error instanceof Response && error.status >= 300 && error.status < 400) throw error;
1182
+ if (!protectionConfig.handleRouteError) throw error;
1183
+ const recovery = await protectionConfig.handleRouteError({
1184
+ ...context,
1185
+ error
1186
+ });
1187
+ if (recovery) throw createRedirectFromConfig(recovery);
1188
+ throw error;
1189
+ }
1190
+ }
1191
+ /**
1192
+ * Main route protection function
1193
+ */
1194
+ async function protectRoute(request, protection, loaderFn) {
1195
+ const url = new URL(request.url);
1196
+ switch (protection) {
1197
+ case "public": try {
1198
+ await autoRefreshTokens(request);
1199
+ return loaderFn(await getUser(request) ?? void 0);
1200
+ } catch {
1201
+ return loaderFn(void 0);
1202
+ }
1203
+ case "auth":
1204
+ case "policy": try {
1205
+ await autoRefreshTokens(request);
1206
+ const user = await requireAuth(request);
1207
+ await applyConfiguredRouteResolution(request, user, url.pathname, protection);
1208
+ return loaderFn(user);
1209
+ } catch (error) {
1210
+ if (error instanceof Response && error.status >= 300 && error.status < 400) throw error;
1211
+ throw await login(request, getLoginReturnUrl(request, url.pathname, protection));
1212
+ }
1213
+ case "onboarding-required": try {
1214
+ await autoRefreshTokens(request);
1215
+ const user = await requireAuth(request);
1216
+ await applyConfiguredRouteResolution(request, user, url.pathname, "onboarding-required");
1217
+ return loaderFn(user);
1218
+ } catch (error) {
1219
+ if (error instanceof Response && error.status >= 300 && error.status < 400) throw error;
1220
+ throw await login(request, getLoginReturnUrl(request, url.pathname, "onboarding-required"));
1221
+ }
1222
+ case "subscription-required": try {
1223
+ await autoRefreshTokens(request);
1224
+ const user = await requireAuth(request);
1225
+ await applyConfiguredRouteResolution(request, user, url.pathname, "subscription-required");
1226
+ if (protectionConfig.tenantChecker) {
1227
+ if (!await protectionConfig.tenantChecker.getCurrentTenant(request)) await protectionConfig.tenantChecker.initializeTenant(request);
1228
+ }
1229
+ return loaderFn(user);
1230
+ } catch (error) {
1231
+ if (error instanceof Response && error.status >= 300 && error.status < 400) throw error;
1232
+ throw await login(request, getLoginReturnUrl(request, url.pathname, "subscription-required"));
1233
+ }
1234
+ default: throw new Error(`Unknown protection level: ${protection}`);
1235
+ }
1236
+ }
1237
+ /**
1238
+ * Public route (optional auth)
1239
+ */
1240
+ const publicRoute = (request, loaderFn) => protectRoute(request, "public", loaderFn);
1241
+ /**
1242
+ * Auth-protected route
1243
+ */
1244
+ const authRoute = (request, loaderFn) => protectRoute(request, "auth", loaderFn);
1245
+ /**
1246
+ * Generic policy-protected route. Apps define policy in configureRouteProtection.
1247
+ */
1248
+ const policyRoute = (request, loaderFn) => protectRoute(request, "policy", loaderFn);
1249
+ /**
1250
+ * Alias for auth-protected routes.
1251
+ */
1252
+ const protectedRoute = authRoute;
1253
+ /**
1254
+ * Setup policy route
1255
+ *
1256
+ * @deprecated Use policyRoute with configureRouteProtection instead.
1257
+ */
1258
+ const onboardingRoute = (request, loaderFn) => protectRoute(request, "onboarding-required", loaderFn);
1259
+ /**
1260
+ * Entitlement policy route
1261
+ *
1262
+ * @deprecated Use policyRoute with configureRouteProtection instead.
1263
+ */
1264
+ const subscriptionRoute = (request, loaderFn) => protectRoute(request, "subscription-required", loaderFn);
1265
+ //#endregion
1266
+ //#region src/auth/token-refresh.server.ts
1267
+ /**
1268
+ * Token Refresh Server Module
1269
+ */
1270
+ /**
1271
+ * Attempt to refresh the access token
1272
+ */
1273
+ async function attemptTokenRefresh(request) {
1274
+ try {
1275
+ logger.info("Attempting token refresh due to 401 response");
1276
+ const sessionData = await getAuthSession(request);
1277
+ if (!sessionData.refreshToken) {
1278
+ logger.warn("No refresh token available in session");
1279
+ return {
1280
+ success: false,
1281
+ error: "No refresh token available",
1282
+ shouldLogout: true
1283
+ };
1284
+ }
1285
+ const refreshResult = await refreshTokens(request, sessionData.refreshToken);
1286
+ if (!refreshResult.success) {
1287
+ logger.error("Token refresh failed", void 0, {
1288
+ error: refreshResult.error,
1289
+ shouldLogout: refreshResult.shouldLogout
1290
+ });
1291
+ return {
1292
+ success: false,
1293
+ error: refreshResult.error,
1294
+ shouldLogout: refreshResult.shouldLogout
1295
+ };
1296
+ }
1297
+ const tokens = refreshResult.tokens;
1298
+ if (!tokens || !tokens.access_token) {
1299
+ logger.error("Token refresh succeeded but no access token returned");
1300
+ return {
1301
+ success: false,
1302
+ error: "No access token in refresh response",
1303
+ shouldLogout: true
1304
+ };
1305
+ }
1306
+ logger.info("Token refresh successful");
1307
+ return {
1308
+ success: true,
1309
+ newAccessToken: tokens.access_token
1310
+ };
1311
+ } catch (error) {
1312
+ logger.error("Token refresh attempt failed", error instanceof Error ? error : void 0);
1313
+ return {
1314
+ success: false,
1315
+ error: error instanceof Error ? error.message : "Unknown error",
1316
+ shouldLogout: true
1317
+ };
1318
+ }
1319
+ }
1320
+ /**
1321
+ * Check if a response indicates token expiration
1322
+ */
1323
+ function isTokenExpiredResponse(response) {
1324
+ return response.status === 401;
1325
+ }
1326
+ /**
1327
+ * Check if token refresh should be attempted
1328
+ */
1329
+ function shouldAttemptTokenRefresh(response, hasAuth) {
1330
+ return hasAuth && isTokenExpiredResponse(response);
1331
+ }
1332
+ //#endregion
1333
+ export { resetAuthClaimMapping as A, handleCallback as C, logout as D, login as E, refreshTokens as O, handleBackChannelLogout as S, hasAuthError as T, createAuthorizationResponseUrl as _, configureRouteProtection as a, getAuthError as b, protectRoute as c, resetRouteProtectionConfig as d, shouldRefreshToken as f, configureAuthClaimMapping as g, clearAuthServerCache as h, authRoute as i, requireAuth as k, protectedRoute as l, clearAuthErrorHeaders as m, isTokenExpiredResponse as n, onboardingRoute as o, subscriptionRoute as p, shouldAttemptTokenRefresh as r, policyRoute as s, attemptTokenRefresh as t, publicRoute as u, extractUserInfo as v, handleFrontChannelLogout as w, getUser as x, getAccessToken as y };
1334
+
1335
+ //# sourceMappingURL=server-CqX2yCa4.mjs.map