@thunderid/nextjs 0.10.3 → 0.10.4

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 (179) hide show
  1. package/dist/ThunderIDNextClient.d.ts +0 -17
  2. package/dist/ThunderIDNextClient.d.ts.map +1 -1
  3. package/dist/ThunderIDNextClient.js.map +1 -1
  4. package/dist/cjs/ThunderIDNextClient.cjs.map +1 -1
  5. package/dist/cjs/client/components/actions/SignInButton/SignInButton.cjs.map +1 -1
  6. package/dist/cjs/client/components/actions/SignOutButton/SignOutButton.cjs.map +1 -1
  7. package/dist/cjs/client/components/actions/SignUpButton/SignUpButton.cjs.map +1 -1
  8. package/dist/cjs/client/components/control/SignedIn/SignedIn.cjs.map +1 -1
  9. package/dist/cjs/client/components/control/SignedOut/SignedOut.cjs.map +1 -1
  10. package/dist/cjs/client/components/presentation/SignIn/SignIn.cjs.map +1 -1
  11. package/dist/cjs/client/components/presentation/SignUp/SignUp.cjs.map +1 -1
  12. package/dist/cjs/client/components/presentation/User/User.cjs.map +1 -1
  13. package/dist/cjs/client/components/presentation/UserAvatar/UserAvatar.cjs.map +1 -1
  14. package/dist/cjs/client/components/presentation/UserDropdown/UserDropdown.cjs.map +1 -1
  15. package/dist/cjs/client/components/presentation/UserProfile/UserProfile.cjs.map +1 -1
  16. package/dist/cjs/client/contexts/ThunderID/ThunderIDContext.cjs.map +1 -1
  17. package/dist/cjs/client/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
  18. package/dist/cjs/client/contexts/ThunderID/useThunderID.cjs.map +1 -1
  19. package/dist/cjs/constants/sessionConstants.cjs +0 -17
  20. package/dist/cjs/constants/sessionConstants.cjs.map +1 -1
  21. package/dist/cjs/server/ThunderIDProvider.cjs.map +1 -1
  22. package/dist/cjs/server/actions/clearSession.cjs.map +1 -1
  23. package/dist/cjs/server/actions/getAccessToken.cjs.map +1 -1
  24. package/dist/cjs/server/actions/getClientOrigin.cjs.map +1 -1
  25. package/dist/cjs/server/actions/getSessionId.cjs.map +1 -1
  26. package/dist/cjs/server/actions/getSessionPayload.cjs.map +1 -1
  27. package/dist/cjs/server/actions/getUserAction.cjs.map +1 -1
  28. package/dist/cjs/server/actions/getUserProfileAction.cjs.map +1 -1
  29. package/dist/cjs/server/actions/handleOAuthCallbackAction.cjs.map +1 -1
  30. package/dist/cjs/server/actions/isSignedIn.cjs.map +1 -1
  31. package/dist/cjs/server/actions/refreshToken.cjs.map +1 -1
  32. package/dist/cjs/server/actions/signInAction.cjs.map +1 -1
  33. package/dist/cjs/server/actions/signOutAction.cjs.map +1 -1
  34. package/dist/cjs/server/actions/signUpAction.cjs.map +1 -1
  35. package/dist/cjs/server/actions/updateUserProfileAction.cjs.map +1 -1
  36. package/dist/cjs/server/getClient.cjs.map +1 -1
  37. package/dist/cjs/server/proxy/createRouteMatcher.cjs.map +1 -1
  38. package/dist/cjs/server/proxy/thunderIDProxy.cjs.map +1 -1
  39. package/dist/cjs/server/thunderid.cjs.map +1 -1
  40. package/dist/cjs/utils/SessionManager.cjs.map +1 -1
  41. package/dist/cjs/utils/decorateConfigWithNextEnv.cjs.map +1 -1
  42. package/dist/cjs/utils/handleRefreshToken.cjs.map +1 -1
  43. package/dist/cjs/utils/logger.cjs.map +1 -1
  44. package/dist/cjs/utils/sessionUtils.cjs.map +1 -1
  45. package/dist/client/components/actions/SignInButton/SignInButton.d.ts +0 -17
  46. package/dist/client/components/actions/SignInButton/SignInButton.d.ts.map +1 -1
  47. package/dist/client/components/actions/SignInButton/SignInButton.js.map +1 -1
  48. package/dist/client/components/actions/SignOutButton/SignOutButton.d.ts +0 -17
  49. package/dist/client/components/actions/SignOutButton/SignOutButton.d.ts.map +1 -1
  50. package/dist/client/components/actions/SignOutButton/SignOutButton.js.map +1 -1
  51. package/dist/client/components/actions/SignUpButton/SignUpButton.d.ts +0 -17
  52. package/dist/client/components/actions/SignUpButton/SignUpButton.d.ts.map +1 -1
  53. package/dist/client/components/actions/SignUpButton/SignUpButton.js.map +1 -1
  54. package/dist/client/components/control/Loading/Loading.d.ts +0 -17
  55. package/dist/client/components/control/Loading/Loading.d.ts.map +1 -1
  56. package/dist/client/components/control/SignedIn/SignedIn.d.ts +0 -17
  57. package/dist/client/components/control/SignedIn/SignedIn.d.ts.map +1 -1
  58. package/dist/client/components/control/SignedIn/SignedIn.js.map +1 -1
  59. package/dist/client/components/control/SignedOut/SignedOut.d.ts +0 -17
  60. package/dist/client/components/control/SignedOut/SignedOut.d.ts.map +1 -1
  61. package/dist/client/components/control/SignedOut/SignedOut.js.map +1 -1
  62. package/dist/client/components/presentation/SignIn/SignIn.d.ts +0 -17
  63. package/dist/client/components/presentation/SignIn/SignIn.d.ts.map +1 -1
  64. package/dist/client/components/presentation/SignIn/SignIn.js.map +1 -1
  65. package/dist/client/components/presentation/SignUp/SignUp.d.ts +0 -17
  66. package/dist/client/components/presentation/SignUp/SignUp.d.ts.map +1 -1
  67. package/dist/client/components/presentation/SignUp/SignUp.js.map +1 -1
  68. package/dist/client/components/presentation/User/User.d.ts +0 -17
  69. package/dist/client/components/presentation/User/User.d.ts.map +1 -1
  70. package/dist/client/components/presentation/User/User.js.map +1 -1
  71. package/dist/client/components/presentation/UserAvatar/UserAvatar.d.ts +0 -17
  72. package/dist/client/components/presentation/UserAvatar/UserAvatar.d.ts.map +1 -1
  73. package/dist/client/components/presentation/UserAvatar/UserAvatar.js.map +1 -1
  74. package/dist/client/components/presentation/UserDropdown/UserDropdown.d.ts +0 -17
  75. package/dist/client/components/presentation/UserDropdown/UserDropdown.d.ts.map +1 -1
  76. package/dist/client/components/presentation/UserDropdown/UserDropdown.js.map +1 -1
  77. package/dist/client/components/presentation/UserProfile/UserProfile.d.ts +0 -17
  78. package/dist/client/components/presentation/UserProfile/UserProfile.d.ts.map +1 -1
  79. package/dist/client/components/presentation/UserProfile/UserProfile.js.map +1 -1
  80. package/dist/client/contexts/ThunderID/ThunderIDContext.d.ts +0 -17
  81. package/dist/client/contexts/ThunderID/ThunderIDContext.d.ts.map +1 -1
  82. package/dist/client/contexts/ThunderID/ThunderIDContext.js.map +1 -1
  83. package/dist/client/contexts/ThunderID/ThunderIDProvider.d.ts +0 -17
  84. package/dist/client/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
  85. package/dist/client/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
  86. package/dist/client/contexts/ThunderID/useThunderID.d.ts +0 -17
  87. package/dist/client/contexts/ThunderID/useThunderID.d.ts.map +1 -1
  88. package/dist/client/contexts/ThunderID/useThunderID.js.map +1 -1
  89. package/dist/client/index.d.ts +0 -17
  90. package/dist/client/index.d.ts.map +1 -1
  91. package/dist/configs/InternalAuthAPIRoutesConfig.d.ts +0 -17
  92. package/dist/configs/InternalAuthAPIRoutesConfig.d.ts.map +1 -1
  93. package/dist/constants/sessionConstants.d.ts +0 -17
  94. package/dist/constants/sessionConstants.d.ts.map +1 -1
  95. package/dist/constants/sessionConstants.js +0 -17
  96. package/dist/constants/sessionConstants.js.map +1 -1
  97. package/dist/index.d.ts +0 -17
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/models/api.d.ts +0 -17
  100. package/dist/models/api.d.ts.map +1 -1
  101. package/dist/models/config.d.ts +0 -17
  102. package/dist/models/config.d.ts.map +1 -1
  103. package/dist/server/ThunderIDProvider.d.ts +0 -17
  104. package/dist/server/ThunderIDProvider.d.ts.map +1 -1
  105. package/dist/server/ThunderIDProvider.js.map +1 -1
  106. package/dist/server/actions/clearSession.d.ts +0 -17
  107. package/dist/server/actions/clearSession.d.ts.map +1 -1
  108. package/dist/server/actions/clearSession.js.map +1 -1
  109. package/dist/server/actions/getAccessToken.d.ts +0 -17
  110. package/dist/server/actions/getAccessToken.d.ts.map +1 -1
  111. package/dist/server/actions/getAccessToken.js.map +1 -1
  112. package/dist/server/actions/getClientOrigin.d.ts +0 -17
  113. package/dist/server/actions/getClientOrigin.d.ts.map +1 -1
  114. package/dist/server/actions/getClientOrigin.js.map +1 -1
  115. package/dist/server/actions/getSessionId.d.ts +0 -17
  116. package/dist/server/actions/getSessionId.d.ts.map +1 -1
  117. package/dist/server/actions/getSessionId.js.map +1 -1
  118. package/dist/server/actions/getSessionPayload.d.ts +0 -17
  119. package/dist/server/actions/getSessionPayload.d.ts.map +1 -1
  120. package/dist/server/actions/getSessionPayload.js.map +1 -1
  121. package/dist/server/actions/getUserAction.d.ts +0 -17
  122. package/dist/server/actions/getUserAction.d.ts.map +1 -1
  123. package/dist/server/actions/getUserAction.js.map +1 -1
  124. package/dist/server/actions/getUserProfileAction.d.ts +0 -17
  125. package/dist/server/actions/getUserProfileAction.d.ts.map +1 -1
  126. package/dist/server/actions/getUserProfileAction.js.map +1 -1
  127. package/dist/server/actions/handleOAuthCallbackAction.d.ts +0 -17
  128. package/dist/server/actions/handleOAuthCallbackAction.d.ts.map +1 -1
  129. package/dist/server/actions/handleOAuthCallbackAction.js.map +1 -1
  130. package/dist/server/actions/isSignedIn.d.ts +0 -17
  131. package/dist/server/actions/isSignedIn.d.ts.map +1 -1
  132. package/dist/server/actions/isSignedIn.js.map +1 -1
  133. package/dist/server/actions/refreshToken.d.ts +0 -17
  134. package/dist/server/actions/refreshToken.d.ts.map +1 -1
  135. package/dist/server/actions/refreshToken.js.map +1 -1
  136. package/dist/server/actions/signInAction.d.ts +0 -17
  137. package/dist/server/actions/signInAction.d.ts.map +1 -1
  138. package/dist/server/actions/signInAction.js.map +1 -1
  139. package/dist/server/actions/signOutAction.d.ts +0 -17
  140. package/dist/server/actions/signOutAction.d.ts.map +1 -1
  141. package/dist/server/actions/signOutAction.js.map +1 -1
  142. package/dist/server/actions/signUpAction.d.ts +0 -17
  143. package/dist/server/actions/signUpAction.d.ts.map +1 -1
  144. package/dist/server/actions/signUpAction.js.map +1 -1
  145. package/dist/server/actions/updateUserProfileAction.d.ts +0 -17
  146. package/dist/server/actions/updateUserProfileAction.d.ts.map +1 -1
  147. package/dist/server/actions/updateUserProfileAction.js.map +1 -1
  148. package/dist/server/getClient.d.ts +0 -17
  149. package/dist/server/getClient.d.ts.map +1 -1
  150. package/dist/server/getClient.js.map +1 -1
  151. package/dist/server/index.d.ts +0 -17
  152. package/dist/server/index.d.ts.map +1 -1
  153. package/dist/server/proxy/createRouteMatcher.d.ts +0 -17
  154. package/dist/server/proxy/createRouteMatcher.d.ts.map +1 -1
  155. package/dist/server/proxy/createRouteMatcher.js.map +1 -1
  156. package/dist/server/proxy/thunderIDProxy.d.ts +0 -17
  157. package/dist/server/proxy/thunderIDProxy.d.ts.map +1 -1
  158. package/dist/server/proxy/thunderIDProxy.js.map +1 -1
  159. package/dist/server/thunderid.d.ts +0 -17
  160. package/dist/server/thunderid.d.ts.map +1 -1
  161. package/dist/server/thunderid.js.map +1 -1
  162. package/dist/utils/SessionManager.d.ts +0 -17
  163. package/dist/utils/SessionManager.d.ts.map +1 -1
  164. package/dist/utils/SessionManager.js.map +1 -1
  165. package/dist/utils/createRouteMatcher.d.ts +0 -17
  166. package/dist/utils/createRouteMatcher.d.ts.map +1 -1
  167. package/dist/utils/decorateConfigWithNextEnv.d.ts +0 -17
  168. package/dist/utils/decorateConfigWithNextEnv.d.ts.map +1 -1
  169. package/dist/utils/decorateConfigWithNextEnv.js.map +1 -1
  170. package/dist/utils/handleRefreshToken.d.ts +0 -17
  171. package/dist/utils/handleRefreshToken.d.ts.map +1 -1
  172. package/dist/utils/handleRefreshToken.js.map +1 -1
  173. package/dist/utils/logger.d.ts +0 -17
  174. package/dist/utils/logger.d.ts.map +1 -1
  175. package/dist/utils/logger.js.map +1 -1
  176. package/dist/utils/sessionUtils.d.ts +0 -17
  177. package/dist/utils/sessionUtils.d.ts.map +1 -1
  178. package/dist/utils/sessionUtils.js.map +1 -1
  179. package/package.json +4 -4
@@ -1,23 +1,6 @@
1
1
 
2
2
  //#region src/constants/sessionConstants.ts
3
3
  /**
4
- * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
5
- *
6
- * WSO2 LLC. licenses this file to you under the Apache License,
7
- * Version 2.0 (the "License"); you may not use this file except
8
- * in compliance with the License.
9
- * You may obtain a copy of the License at
10
- *
11
- * http://www.apache.org/licenses/LICENSE-2.0
12
- *
13
- * Unless required by applicable law or agreed to in writing,
14
- * software distributed under the License is distributed on an
15
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
- * KIND, either express or implied. See the License for the
17
- * specific language governing permissions and limitations
18
- * under the License.
19
- */
20
- /**
21
4
  * Number of seconds before access token expiry at which the SDK proactively
22
5
  * refreshes the token. A 25-second buffer prevents races where the token is
23
6
  * valid when a request starts but expires mid-flight.
@@ -1 +1 @@
1
- {"version":3,"file":"sessionConstants.cjs","names":[],"sources":["../../../src/constants/sessionConstants.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n/**\n * Number of seconds before access token expiry at which the SDK proactively\n * refreshes the token. A 25-second buffer prevents races where the token is\n * valid when a request starts but expires mid-flight.\n */\nexport const REFRESH_BUFFER_SECONDS = 25;\n\n/**\n * Default session cookie lifetime in seconds (24 hours).\n *\n * Used when no explicit session cookie expiry is configured. The session cookie\n * lifetime can be overridden in two ways (evaluated in this order):\n *\n * 1. `sessionCookie.expiryTime` in `ThunderIDNodeConfig` — set programmatically\n * when initialising the SDK.\n * 2. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME` environment variable — set in `.env`\n * (e.g. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME=86400`).\n * 3. This constant — applied when neither of the above is present.\n *\n * Two independent expiry bounds apply to the session and they are generally\n * NOT the same value:\n *\n * - JWT `exp` claim — set by `SessionManager.createSessionToken(...)` from\n * the `accessTokenTtlSeconds` argument (i.e. the access token's `expires_in`\n * returned by the auth server, typically ~1 hour). This controls when\n * `verifySessionToken` rejects the token and is the trigger for a refresh.\n * - Browser cookie `maxAge` — set by the caller (sign-in / refresh / org-switch\n * actions) from `SessionManager.resolveSessionCookieExpiry(...)`, which returns\n * this constant by default (24 hours). This controls how long the browser\n * holds the cookie before discarding it.\n */\nexport const DEFAULT_SESSION_COOKIE_EXPIRY_TIME = 86400;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BtC,MAAa,qCAAqC"}
1
+ {"version":3,"file":"sessionConstants.cjs","names":[],"sources":["../../../src/constants/sessionConstants.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Number of seconds before access token expiry at which the SDK proactively\n * refreshes the token. A 25-second buffer prevents races where the token is\n * valid when a request starts but expires mid-flight.\n */\nexport const REFRESH_BUFFER_SECONDS = 25;\n\n/**\n * Default session cookie lifetime in seconds (24 hours).\n *\n * Used when no explicit session cookie expiry is configured. The session cookie\n * lifetime can be overridden in two ways (evaluated in this order):\n *\n * 1. `sessionCookie.expiryTime` in `ThunderIDNodeConfig` — set programmatically\n * when initialising the SDK.\n * 2. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME` environment variable — set in `.env`\n * (e.g. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME=86400`).\n * 3. This constant — applied when neither of the above is present.\n *\n * Two independent expiry bounds apply to the session and they are generally\n * NOT the same value:\n *\n * - JWT `exp` claim — set by `SessionManager.createSessionToken(...)` from\n * the `accessTokenTtlSeconds` argument (i.e. the access token's `expires_in`\n * returned by the auth server, typically ~1 hour). This controls when\n * `verifySessionToken` rejects the token and is the trigger for a refresh.\n * - Browser cookie `maxAge` — set by the caller (sign-in / refresh / org-switch\n * actions) from `SessionManager.resolveSessionCookieExpiry(...)`, which returns\n * this constant by default (24 hours). This controls how long the browser\n * holds the cookie before discarding it.\n */\nexport const DEFAULT_SESSION_COOKIE_EXPIRY_TIME = 86400;\n"],"mappings":";;;;;;;AAQA,MAAa,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BtC,MAAa,qCAAqC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDProvider.cjs","names":["ThunderIDServerProvider: FC<PropsWithChildren<ThunderIDServerProviderProps>>","getClient","config: Partial<ThunderIDNextConfig>","ThunderIDRuntimeError","flowMeta: FlowMetadataResponse | null","FlowMetaType","sessionPayload: SessionTokenPayload | undefined","getSessionPayload","sessionId: string","getSessionId","signedIn: boolean","isSignedIn","user: User","userProfile: UserProfile","updatedBaseUrl: string | undefined","userResponse: {\n data: {user: User | null};\n error: string | null;\n success: boolean;\n }","getUserAction","userProfileResponse: {\n data: {userProfile: UserProfile};\n error: string | null;\n success: boolean;\n }","getUserProfileAction","ThunderIDClientProvider","signInAction","clearSession","refreshToken","signOutAction","signUpAction","handleOAuthCallbackAction","updateUserProfileAction"],"sources":["../../../src/server/ThunderIDProvider.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {\n ThunderIDRuntimeError,\n FlowMetadataResponse,\n FlowMetaType,\n IdToken,\n User,\n UserProfile,\n getFlowMeta,\n extractUserClaimsFromIdToken,\n resolveResourceEndpoint,\n} from '@thunderid/node';\nimport {ThunderIDProviderProps} from '@thunderid/react';\nimport {FC, PropsWithChildren, ReactElement} from 'react';\nimport clearSession from './actions/clearSession';\nimport getSessionId from './actions/getSessionId';\nimport getSessionPayload from './actions/getSessionPayload';\nimport getUserAction from './actions/getUserAction';\nimport getUserProfileAction from './actions/getUserProfileAction';\nimport handleOAuthCallbackAction from './actions/handleOAuthCallbackAction';\nimport isSignedIn from './actions/isSignedIn';\nimport refreshToken from './actions/refreshToken';\nimport signInAction from './actions/signInAction';\nimport signOutAction from './actions/signOutAction';\nimport signUpAction from './actions/signUpAction';\nimport updateUserProfileAction from './actions/updateUserProfileAction';\nimport getClient from './getClient';\nimport ThunderIDClientProvider from '../client/contexts/ThunderID/ThunderIDProvider.js';\nimport {ThunderIDNextConfig} from '../models/config';\nimport logger from '../utils/logger';\nimport {SessionTokenPayload} from '../utils/SessionManager';\n\n/**\n * Props interface of {@link ThunderIDServerProvider}\n */\nexport type ThunderIDServerProviderProps = Partial<ThunderIDProviderProps> & {\n clientSecret?: string;\n /**\n * Session cookie lifetime in seconds. Determines how long the session cookie\n * remains valid in the browser after sign-in.\n *\n * Resolution order (first defined value wins):\n * 1. This prop — set here when mounting the provider.\n * 2. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME` environment variable.\n * 3. Built-in default of 86400 seconds (24 hours).\n *\n * @example\n * // 8-hour session cookie\n * <ThunderIDServerProvider sessionCookieExpiryTime={28800} ... />\n */\n sessionCookieExpiryTime?: number;\n};\n\n/**\n * Server-side provider component for ThunderID authentication.\n * Wraps the client-side provider and handles server-side authentication logic.\n * Uses the singleton ThunderIDNextClient instance for consistent authentication state.\n *\n * @param props - Props injected into the component.\n *\n * @example\n * ```tsx\n * <ThunderIDServerProvider config={thunderidConfig}>\n * <YourApp />\n * </ThunderIDServerProvider>\n * ```\n *\n * @returns ThunderIDServerProvider component.\n */\nconst ThunderIDServerProvider: FC<PropsWithChildren<ThunderIDServerProviderProps>> = async ({\n children,\n afterSignInUrl,\n afterSignOutUrl,\n ..._config\n}: PropsWithChildren<ThunderIDServerProviderProps>): Promise<ReactElement> => {\n const thunderIDClient = getClient();\n let config: Partial<ThunderIDNextConfig> = {};\n\n try {\n await thunderIDClient.initialize(_config as ThunderIDNextConfig);\n\n logger.debug('[ThunderIDServerProvider] ThunderID client initialized successfully.');\n\n config = await thunderIDClient.getConfiguration();\n } catch (error) {\n logger.error('[ThunderIDServerProvider] Failed to initialize ThunderID client:', error?.toString());\n\n throw new ThunderIDRuntimeError(\n `Failed to initialize ThunderID client: ${error?.toString()}`,\n 'next-ConfigurationError-001',\n 'next',\n 'An error occurred while initializing the ThunderID client. Please check your configuration.',\n );\n }\n\n if (!thunderIDClient.isInitialized) {\n return <></>;\n }\n\n // Fetch flow metadata (design config + i18n bundle) server-side so `FlowMetaProvider` can seed\n // its state and skip a redundant client-side fetch — avoiding a flash of untranslated i18n keys\n // (e.g. raw `signin.forms.credentials.title`) while embedded flow components first render.\n let flowMeta: FlowMetadataResponse | null = null;\n try {\n flowMeta = await getFlowMeta({\n baseUrl: config?.baseUrl,\n url: resolveResourceEndpoint('flowMeta', config),\n ...(config?.applicationId ? {id: config.applicationId, type: FlowMetaType.App} : {}),\n });\n } catch (error) {\n logger.warn('[ThunderIDServerProvider] Failed to fetch flow metadata:', error?.toString());\n }\n\n // Try to get session information from JWT first, then fall back to legacy\n const sessionPayload: SessionTokenPayload | undefined = await getSessionPayload();\n const sessionId: string = sessionPayload?.sessionId || (await getSessionId()) || '';\n const signedIn: boolean = await isSignedIn(sessionId);\n\n let user: User = {};\n let userProfile: UserProfile = {\n flattenedProfile: {},\n profile: {},\n };\n\n const resolvedPreferences = {\n ...config?.preferences,\n ..._config.preferences,\n user: {\n ...config?.preferences?.user,\n ..._config.preferences?.user,\n },\n };\n\n if (signedIn) {\n let updatedBaseUrl: string | undefined = config?.baseUrl;\n\n if (sessionPayload?.organizationId) {\n updatedBaseUrl = `${config?.baseUrl}/o`;\n config = {...config, baseUrl: updatedBaseUrl};\n } else if (sessionId) {\n try {\n const idToken: IdToken = await thunderIDClient.getDecodedIdToken(sessionId);\n if (idToken?.['user_org']) {\n updatedBaseUrl = `${config?.baseUrl}/o`;\n config = {...config, baseUrl: updatedBaseUrl};\n }\n } catch {\n // Continue without organization info\n }\n }\n\n // Check if user profile fetching is enabled (default: true)\n const shouldFetchUserProfile: boolean = resolvedPreferences?.user?.fetchUserProfile !== false;\n\n if (shouldFetchUserProfile) {\n try {\n const userResponse: {\n data: {user: User | null};\n error: string | null;\n success: boolean;\n } = await getUserAction(sessionId);\n const userProfileResponse: {\n data: {userProfile: UserProfile};\n error: string | null;\n success: boolean;\n } = await getUserProfileAction(sessionId);\n\n user = userResponse.data?.user || {};\n userProfile = userProfileResponse.data?.userProfile ?? userProfile;\n } catch (error) {\n logger.warn('[ThunderIDServerProvider] Failed to fetch user profile from /users/me:', error?.toString());\n }\n } else {\n try {\n const decodedIdToken: IdToken = await thunderIDClient.getDecodedIdToken(sessionId);\n const claims = extractUserClaimsFromIdToken(decodedIdToken);\n user = claims;\n userProfile = {\n flattenedProfile: claims,\n profile: claims,\n };\n } catch (error) {\n logger.warn('[ThunderIDServerProvider] Failed to extract user claims from ID token:', error?.toString());\n }\n }\n }\n\n return (\n <ThunderIDClientProvider\n organizationHandle={config?.organizationHandle}\n applicationId={config?.applicationId}\n baseUrl={config?.baseUrl}\n initialMeta={flowMeta}\n signIn={signInAction}\n clearSession={clearSession}\n refreshToken={refreshToken}\n signOut={signOutAction}\n signUp={signUpAction}\n handleOAuthCallback={handleOAuthCallbackAction}\n signInUrl={config?.signInUrl}\n signUpUrl={config?.signUpUrl}\n preferences={resolvedPreferences}\n clientId={config?.clientId}\n user={user}\n userProfile={userProfile}\n updateProfile={updateUserProfileAction}\n isSignedIn={signedIn}\n >\n {children}\n </ThunderIDClientProvider>\n );\n};\n\nexport default ThunderIDServerProvider;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwFA,MAAMA,0BAA+E,OAAO,EAC1F,UACA,gBACA,gBACA,GAAG,cACyE;CAC5E,MAAM,kBAAkBC,2BAAW;CACnC,IAAIC,SAAuC,EAAE;AAE7C,KAAI;AACF,QAAM,gBAAgB,WAAW,QAA+B;AAEhE,yBAAO,MAAM,uEAAuE;AAEpF,WAAS,MAAM,gBAAgB,kBAAkB;UAC1C,OAAO;AACd,yBAAO,MAAM,oEAAoE,OAAO,UAAU,CAAC;AAEnG,QAAM,IAAIC,uCACR,0CAA0C,OAAO,UAAU,IAC3D,+BACA,QACA,8FACD;;AAGH,KAAI,CAAC,gBAAgB,cACnB,QAAO,0EAAK;CAMd,IAAIC,WAAwC;AAC5C,KAAI;AACF,aAAW,wCAAkB;GAC3B,SAAS,QAAQ;GACjB,mDAA6B,YAAY,OAAO;GAChD,GAAI,QAAQ,gBAAgB;IAAC,IAAI,OAAO;IAAe,MAAMC,8BAAa;IAAI,GAAG,EAAE;GACpF,CAAC;UACK,OAAO;AACd,yBAAO,KAAK,4DAA4D,OAAO,UAAU,CAAC;;CAI5F,MAAMC,iBAAkD,MAAMC,mCAAmB;CACjF,MAAMC,YAAoB,gBAAgB,aAAc,MAAMC,8BAAc,IAAK;CACjF,MAAMC,WAAoB,MAAMC,2BAAW,UAAU;CAErD,IAAIC,OAAa,EAAE;CACnB,IAAIC,cAA2B;EAC7B,kBAAkB,EAAE;EACpB,SAAS,EAAE;EACZ;CAED,MAAM,sBAAsB;EAC1B,GAAG,QAAQ;EACX,GAAG,QAAQ;EACX,MAAM;GACJ,GAAG,QAAQ,aAAa;GACxB,GAAG,QAAQ,aAAa;GACzB;EACF;AAED,KAAI,UAAU;EACZ,IAAIC,iBAAqC,QAAQ;AAEjD,MAAI,gBAAgB,gBAAgB;AAClC,oBAAiB,GAAG,QAAQ,QAAQ;AACpC,YAAS;IAAC,GAAG;IAAQ,SAAS;IAAe;aACpC,UACT,KAAI;AAEF,QADyB,MAAM,gBAAgB,kBAAkB,UAAU,IAC7D,aAAa;AACzB,qBAAiB,GAAG,QAAQ,QAAQ;AACpC,aAAS;KAAC,GAAG;KAAQ,SAAS;KAAe;;UAEzC;AAQV,MAFwC,qBAAqB,MAAM,qBAAqB,MAGtF,KAAI;GACF,MAAMC,eAIF,MAAMC,8BAAc,UAAU;GAClC,MAAMC,sBAIF,MAAMC,qCAAqB,UAAU;AAEzC,UAAO,aAAa,MAAM,QAAQ,EAAE;AACpC,iBAAc,oBAAoB,MAAM,eAAe;WAChD,OAAO;AACd,0BAAO,KAAK,0EAA0E,OAAO,UAAU,CAAC;;MAG1G,KAAI;GAEF,MAAM,4DAD0B,MAAM,gBAAgB,kBAAkB,UAAU,CACvB;AAC3D,UAAO;AACP,iBAAc;IACZ,kBAAkB;IAClB,SAAS;IACV;WACM,OAAO;AACd,0BAAO,KAAK,0EAA0E,OAAO,UAAU,CAAC;;;AAK9G,QACE,2CAACC;EACC,oBAAoB,QAAQ;EAC5B,eAAe,QAAQ;EACvB,SAAS,QAAQ;EACjB,aAAa;EACb,QAAQC;EACR,cAAcC;EACd,cAAcC;EACd,SAASC;EACT,QAAQC;EACR,qBAAqBC;EACrB,WAAW,QAAQ;EACnB,WAAW,QAAQ;EACnB,aAAa;EACb,UAAU,QAAQ;EACZ;EACO;EACb,eAAeC;EACf,YAAY;EAEX;GACuB;;AAI9B,kCAAe"}
1
+ {"version":3,"file":"ThunderIDProvider.cjs","names":["ThunderIDServerProvider: FC<PropsWithChildren<ThunderIDServerProviderProps>>","getClient","config: Partial<ThunderIDNextConfig>","ThunderIDRuntimeError","flowMeta: FlowMetadataResponse | null","FlowMetaType","sessionPayload: SessionTokenPayload | undefined","getSessionPayload","sessionId: string","getSessionId","signedIn: boolean","isSignedIn","user: User","userProfile: UserProfile","updatedBaseUrl: string | undefined","userResponse: {\n data: {user: User | null};\n error: string | null;\n success: boolean;\n }","getUserAction","userProfileResponse: {\n data: {userProfile: UserProfile};\n error: string | null;\n success: boolean;\n }","getUserProfileAction","ThunderIDClientProvider","signInAction","clearSession","refreshToken","signOutAction","signUpAction","handleOAuthCallbackAction","updateUserProfileAction"],"sources":["../../../src/server/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {\n ThunderIDRuntimeError,\n FlowMetadataResponse,\n FlowMetaType,\n IdToken,\n User,\n UserProfile,\n getFlowMeta,\n extractUserClaimsFromIdToken,\n resolveResourceEndpoint,\n} from '@thunderid/node';\nimport {ThunderIDProviderProps} from '@thunderid/react';\nimport {FC, PropsWithChildren, ReactElement} from 'react';\nimport clearSession from './actions/clearSession';\nimport getSessionId from './actions/getSessionId';\nimport getSessionPayload from './actions/getSessionPayload';\nimport getUserAction from './actions/getUserAction';\nimport getUserProfileAction from './actions/getUserProfileAction';\nimport handleOAuthCallbackAction from './actions/handleOAuthCallbackAction';\nimport isSignedIn from './actions/isSignedIn';\nimport refreshToken from './actions/refreshToken';\nimport signInAction from './actions/signInAction';\nimport signOutAction from './actions/signOutAction';\nimport signUpAction from './actions/signUpAction';\nimport updateUserProfileAction from './actions/updateUserProfileAction';\nimport getClient from './getClient';\nimport ThunderIDClientProvider from '../client/contexts/ThunderID/ThunderIDProvider.js';\nimport {ThunderIDNextConfig} from '../models/config';\nimport logger from '../utils/logger';\nimport {SessionTokenPayload} from '../utils/SessionManager';\n\n/**\n * Props interface of {@link ThunderIDServerProvider}\n */\nexport type ThunderIDServerProviderProps = Partial<ThunderIDProviderProps> & {\n clientSecret?: string;\n /**\n * Session cookie lifetime in seconds. Determines how long the session cookie\n * remains valid in the browser after sign-in.\n *\n * Resolution order (first defined value wins):\n * 1. This prop — set here when mounting the provider.\n * 2. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME` environment variable.\n * 3. Built-in default of 86400 seconds (24 hours).\n *\n * @example\n * // 8-hour session cookie\n * <ThunderIDServerProvider sessionCookieExpiryTime={28800} ... />\n */\n sessionCookieExpiryTime?: number;\n};\n\n/**\n * Server-side provider component for ThunderID authentication.\n * Wraps the client-side provider and handles server-side authentication logic.\n * Uses the singleton ThunderIDNextClient instance for consistent authentication state.\n *\n * @param props - Props injected into the component.\n *\n * @example\n * ```tsx\n * <ThunderIDServerProvider config={thunderidConfig}>\n * <YourApp />\n * </ThunderIDServerProvider>\n * ```\n *\n * @returns ThunderIDServerProvider component.\n */\nconst ThunderIDServerProvider: FC<PropsWithChildren<ThunderIDServerProviderProps>> = async ({\n children,\n afterSignInUrl,\n afterSignOutUrl,\n ..._config\n}: PropsWithChildren<ThunderIDServerProviderProps>): Promise<ReactElement> => {\n const thunderIDClient = getClient();\n let config: Partial<ThunderIDNextConfig> = {};\n\n try {\n await thunderIDClient.initialize(_config as ThunderIDNextConfig);\n\n logger.debug('[ThunderIDServerProvider] ThunderID client initialized successfully.');\n\n config = await thunderIDClient.getConfiguration();\n } catch (error) {\n logger.error('[ThunderIDServerProvider] Failed to initialize ThunderID client:', error?.toString());\n\n throw new ThunderIDRuntimeError(\n `Failed to initialize ThunderID client: ${error?.toString()}`,\n 'next-ConfigurationError-001',\n 'next',\n 'An error occurred while initializing the ThunderID client. Please check your configuration.',\n );\n }\n\n if (!thunderIDClient.isInitialized) {\n return <></>;\n }\n\n // Fetch flow metadata (design config + i18n bundle) server-side so `FlowMetaProvider` can seed\n // its state and skip a redundant client-side fetch — avoiding a flash of untranslated i18n keys\n // (e.g. raw `signin.forms.credentials.title`) while embedded flow components first render.\n let flowMeta: FlowMetadataResponse | null = null;\n try {\n flowMeta = await getFlowMeta({\n baseUrl: config?.baseUrl,\n url: resolveResourceEndpoint('flowMeta', config),\n ...(config?.applicationId ? {id: config.applicationId, type: FlowMetaType.App} : {}),\n });\n } catch (error) {\n logger.warn('[ThunderIDServerProvider] Failed to fetch flow metadata:', error?.toString());\n }\n\n // Try to get session information from JWT first, then fall back to legacy\n const sessionPayload: SessionTokenPayload | undefined = await getSessionPayload();\n const sessionId: string = sessionPayload?.sessionId || (await getSessionId()) || '';\n const signedIn: boolean = await isSignedIn(sessionId);\n\n let user: User = {};\n let userProfile: UserProfile = {\n flattenedProfile: {},\n profile: {},\n };\n\n const resolvedPreferences = {\n ...config?.preferences,\n ..._config.preferences,\n user: {\n ...config?.preferences?.user,\n ..._config.preferences?.user,\n },\n };\n\n if (signedIn) {\n let updatedBaseUrl: string | undefined = config?.baseUrl;\n\n if (sessionPayload?.organizationId) {\n updatedBaseUrl = `${config?.baseUrl}/o`;\n config = {...config, baseUrl: updatedBaseUrl};\n } else if (sessionId) {\n try {\n const idToken: IdToken = await thunderIDClient.getDecodedIdToken(sessionId);\n if (idToken?.['user_org']) {\n updatedBaseUrl = `${config?.baseUrl}/o`;\n config = {...config, baseUrl: updatedBaseUrl};\n }\n } catch {\n // Continue without organization info\n }\n }\n\n // Check if user profile fetching is enabled (default: true)\n const shouldFetchUserProfile: boolean = resolvedPreferences?.user?.fetchUserProfile !== false;\n\n if (shouldFetchUserProfile) {\n try {\n const userResponse: {\n data: {user: User | null};\n error: string | null;\n success: boolean;\n } = await getUserAction(sessionId);\n const userProfileResponse: {\n data: {userProfile: UserProfile};\n error: string | null;\n success: boolean;\n } = await getUserProfileAction(sessionId);\n\n user = userResponse.data?.user || {};\n userProfile = userProfileResponse.data?.userProfile ?? userProfile;\n } catch (error) {\n logger.warn('[ThunderIDServerProvider] Failed to fetch user profile from /users/me:', error?.toString());\n }\n } else {\n try {\n const decodedIdToken: IdToken = await thunderIDClient.getDecodedIdToken(sessionId);\n const claims = extractUserClaimsFromIdToken(decodedIdToken);\n user = claims;\n userProfile = {\n flattenedProfile: claims,\n profile: claims,\n };\n } catch (error) {\n logger.warn('[ThunderIDServerProvider] Failed to extract user claims from ID token:', error?.toString());\n }\n }\n }\n\n return (\n <ThunderIDClientProvider\n organizationHandle={config?.organizationHandle}\n applicationId={config?.applicationId}\n baseUrl={config?.baseUrl}\n initialMeta={flowMeta}\n signIn={signInAction}\n clearSession={clearSession}\n refreshToken={refreshToken}\n signOut={signOutAction}\n signUp={signUpAction}\n handleOAuthCallback={handleOAuthCallbackAction}\n signInUrl={config?.signInUrl}\n signUpUrl={config?.signUpUrl}\n preferences={resolvedPreferences}\n clientId={config?.clientId}\n user={user}\n userProfile={userProfile}\n updateProfile={updateUserProfileAction}\n isSignedIn={signedIn}\n >\n {children}\n </ThunderIDClientProvider>\n );\n};\n\nexport default ThunderIDServerProvider;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEA,MAAMA,0BAA+E,OAAO,EAC1F,UACA,gBACA,gBACA,GAAG,cACyE;CAC5E,MAAM,kBAAkBC,2BAAW;CACnC,IAAIC,SAAuC,EAAE;AAE7C,KAAI;AACF,QAAM,gBAAgB,WAAW,QAA+B;AAEhE,yBAAO,MAAM,uEAAuE;AAEpF,WAAS,MAAM,gBAAgB,kBAAkB;UAC1C,OAAO;AACd,yBAAO,MAAM,oEAAoE,OAAO,UAAU,CAAC;AAEnG,QAAM,IAAIC,uCACR,0CAA0C,OAAO,UAAU,IAC3D,+BACA,QACA,8FACD;;AAGH,KAAI,CAAC,gBAAgB,cACnB,QAAO,0EAAK;CAMd,IAAIC,WAAwC;AAC5C,KAAI;AACF,aAAW,wCAAkB;GAC3B,SAAS,QAAQ;GACjB,mDAA6B,YAAY,OAAO;GAChD,GAAI,QAAQ,gBAAgB;IAAC,IAAI,OAAO;IAAe,MAAMC,8BAAa;IAAI,GAAG,EAAE;GACpF,CAAC;UACK,OAAO;AACd,yBAAO,KAAK,4DAA4D,OAAO,UAAU,CAAC;;CAI5F,MAAMC,iBAAkD,MAAMC,mCAAmB;CACjF,MAAMC,YAAoB,gBAAgB,aAAc,MAAMC,8BAAc,IAAK;CACjF,MAAMC,WAAoB,MAAMC,2BAAW,UAAU;CAErD,IAAIC,OAAa,EAAE;CACnB,IAAIC,cAA2B;EAC7B,kBAAkB,EAAE;EACpB,SAAS,EAAE;EACZ;CAED,MAAM,sBAAsB;EAC1B,GAAG,QAAQ;EACX,GAAG,QAAQ;EACX,MAAM;GACJ,GAAG,QAAQ,aAAa;GACxB,GAAG,QAAQ,aAAa;GACzB;EACF;AAED,KAAI,UAAU;EACZ,IAAIC,iBAAqC,QAAQ;AAEjD,MAAI,gBAAgB,gBAAgB;AAClC,oBAAiB,GAAG,QAAQ,QAAQ;AACpC,YAAS;IAAC,GAAG;IAAQ,SAAS;IAAe;aACpC,UACT,KAAI;AAEF,QADyB,MAAM,gBAAgB,kBAAkB,UAAU,IAC7D,aAAa;AACzB,qBAAiB,GAAG,QAAQ,QAAQ;AACpC,aAAS;KAAC,GAAG;KAAQ,SAAS;KAAe;;UAEzC;AAQV,MAFwC,qBAAqB,MAAM,qBAAqB,MAGtF,KAAI;GACF,MAAMC,eAIF,MAAMC,8BAAc,UAAU;GAClC,MAAMC,sBAIF,MAAMC,qCAAqB,UAAU;AAEzC,UAAO,aAAa,MAAM,QAAQ,EAAE;AACpC,iBAAc,oBAAoB,MAAM,eAAe;WAChD,OAAO;AACd,0BAAO,KAAK,0EAA0E,OAAO,UAAU,CAAC;;MAG1G,KAAI;GAEF,MAAM,4DAD0B,MAAM,gBAAgB,kBAAkB,UAAU,CACvB;AAC3D,UAAO;AACP,iBAAc;IACZ,kBAAkB;IAClB,SAAS;IACV;WACM,OAAO;AACd,0BAAO,KAAK,0EAA0E,OAAO,UAAU,CAAC;;;AAK9G,QACE,2CAACC;EACC,oBAAoB,QAAQ;EAC5B,eAAe,QAAQ;EACvB,SAAS,QAAQ;EACjB,aAAa;EACb,QAAQC;EACR,cAAcC;EACd,cAAcC;EACd,SAASC;EACT,QAAQC;EACR,qBAAqBC;EACrB,WAAW,QAAQ;EACnB,WAAW,QAAQ;EACnB,aAAa;EACb,UAAU,QAAQ;EACZ;EACO;EACb,eAAeC;EACf,YAAY;EAEX;GACuB;;AAI9B,kCAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"clearSession.cjs","names":["cookieStore: RequestCookies","SessionManager"],"sources":["../../../../src/server/actions/clearSession.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport logger from '../../utils/logger';\nimport SessionManager from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Deletes all ThunderID session cookies from the browser without contacting the\n * identity server.\n *\n * Use this for error-recovery scenarios where the local session must be wiped\n * immediately: refresh token failures, corrupt sessions, or forced local sign-out\n * when the identity server is unreachable.\n *\n * For a complete sign-out that also revokes the server-side session and obtains the\n * after-sign-out redirect URL, use `signOutAction` instead.\n *\n * @example\n * ```typescript\n * import { clearSession } from '@thunderid/nextjs/server';\n *\n * // Inside a Server Action or Route Handler:\n * await clearSession();\n * redirect('/sign-in');\n * ```\n */\nconst clearSession = async (): Promise<void> => {\n const cookieStore: RequestCookies = await cookies();\n cookieStore.delete(SessionManager.getSessionCookieName());\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n logger.debug('[clearSession] Session cookies cleared.');\n};\n\nexport default clearSession;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,eAAe,YAA2B;CAC9C,MAAMA,cAA8B,iCAAe;AACnD,aAAY,OAAOC,+BAAe,sBAAsB,CAAC;AACzD,aAAY,OAAOA,+BAAe,0BAA0B,CAAC;AAC7D,wBAAO,MAAM,0CAA0C;;AAGzD,2BAAe"}
1
+ {"version":3,"file":"clearSession.cjs","names":["cookieStore: RequestCookies","SessionManager"],"sources":["../../../../src/server/actions/clearSession.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport logger from '../../utils/logger';\nimport SessionManager from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Deletes all ThunderID session cookies from the browser without contacting the\n * identity server.\n *\n * Use this for error-recovery scenarios where the local session must be wiped\n * immediately: refresh token failures, corrupt sessions, or forced local sign-out\n * when the identity server is unreachable.\n *\n * For a complete sign-out that also revokes the server-side session and obtains the\n * after-sign-out redirect URL, use `signOutAction` instead.\n *\n * @example\n * ```typescript\n * import { clearSession } from '@thunderid/nextjs/server';\n *\n * // Inside a Server Action or Route Handler:\n * await clearSession();\n * redirect('/sign-in');\n * ```\n */\nconst clearSession = async (): Promise<void> => {\n const cookieStore: RequestCookies = await cookies();\n cookieStore.delete(SessionManager.getSessionCookieName());\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n logger.debug('[clearSession] Session cookies cleared.');\n};\n\nexport default clearSession;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,eAAe,YAA2B;CAC9C,MAAMA,cAA8B,iCAAe;AACnD,aAAY,OAAOC,+BAAe,sBAAsB,CAAC;AACzD,aAAY,OAAOA,+BAAe,0BAA0B,CAAC;AAC7D,wBAAO,MAAM,0CAA0C;;AAGzD,2BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getAccessToken.cjs","names":["sessionToken: string | undefined","SessionManager"],"sources":["../../../../src/server/actions/getAccessToken.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Get the access token from the session cookie.\n *\n * @returns The access token if it exists, undefined otherwise\n */\nconst getAccessToken = async (): Promise<string | undefined> => {\n const cookieStore: RequestCookies = await cookies();\n\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (sessionToken) {\n try {\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionToken(sessionToken);\n\n return sessionPayload['accessToken'] as string;\n } catch (error) {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport default getAccessToken;\n"],"mappings":";;;;;;;;;;;;;;AA8BA,MAAM,iBAAiB,YAAyC;CAG9D,MAAMA,gBAF8B,iCAAe,EAEE,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEjG,KAAI,aACF,KAAI;AAGF,UAF4C,MAAMA,+BAAe,mBAAmB,aAAa,EAE3E;UACf,OAAO;AACd;;;AAON,6BAAe"}
1
+ {"version":3,"file":"getAccessToken.cjs","names":["sessionToken: string | undefined","SessionManager"],"sources":["../../../../src/server/actions/getAccessToken.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Get the access token from the session cookie.\n *\n * @returns The access token if it exists, undefined otherwise\n */\nconst getAccessToken = async (): Promise<string | undefined> => {\n const cookieStore: RequestCookies = await cookies();\n\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (sessionToken) {\n try {\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionToken(sessionToken);\n\n return sessionPayload['accessToken'] as string;\n } catch (error) {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport default getAccessToken;\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAM,iBAAiB,YAAyC;CAG9D,MAAMA,gBAF8B,iCAAe,EAEE,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEjG,KAAI,aACF,KAAI;AAGF,UAF4C,MAAMA,+BAAe,mBAAmB,aAAa,EAE3E;UACf,OAAO;AACd;;;AAON,6BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getClientOrigin.cjs","names":["headersList: ReadonlyHeaders","host: string | null"],"sources":["../../../../src/server/actions/getClientOrigin.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {ReadonlyHeaders} from 'next/dist/server/web/spec-extension/adapters/headers';\nimport {headers} from 'next/headers';\n\nconst getClientOrigin = async (): Promise<string> => {\n const headersList: ReadonlyHeaders = await headers();\n const host: string | null = headersList.get('host');\n const protocol: string = headersList.get('x-forwarded-proto') ?? 'http';\n return `${protocol}://${host}`;\n};\n\nexport default getClientOrigin;\n"],"mappings":";;;;;;;;AAuBA,MAAM,kBAAkB,YAA6B;CACnD,MAAMA,cAA+B,iCAAe;CACpD,MAAMC,OAAsB,YAAY,IAAI,OAAO;AAEnD,QAAO,GADkB,YAAY,IAAI,oBAAoB,IAAI,OAC9C,KAAK;;AAG1B,8BAAe"}
1
+ {"version":3,"file":"getClientOrigin.cjs","names":["headersList: ReadonlyHeaders","host: string | null"],"sources":["../../../../src/server/actions/getClientOrigin.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {ReadonlyHeaders} from 'next/dist/server/web/spec-extension/adapters/headers';\nimport {headers} from 'next/headers';\n\nconst getClientOrigin = async (): Promise<string> => {\n const headersList: ReadonlyHeaders = await headers();\n const host: string | null = headersList.get('host');\n const protocol: string = headersList.get('x-forwarded-proto') ?? 'http';\n return `${protocol}://${host}`;\n};\n\nexport default getClientOrigin;\n"],"mappings":";;;;;;;;AAQA,MAAM,kBAAkB,YAA6B;CACnD,MAAMA,cAA+B,iCAAe;CACpD,MAAMC,OAAsB,YAAY,IAAI,OAAO;AAEnD,QAAO,GADkB,YAAY,IAAI,oBAAoB,IAAI,OAC9C,KAAK;;AAG1B,8BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getSessionId.cjs","names":["sessionToken: string | undefined","SessionManager"],"sources":["../../../../src/server/actions/getSessionId.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Get the session ID from cookies.\n * Tries JWT session first, then falls back to legacy session ID.\n *\n * @returns The session ID if it exists, undefined otherwise\n */\nconst getSessionId = async (): Promise<string | undefined> => {\n const cookieStore: RequestCookies = await cookies();\n\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (sessionToken) {\n try {\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionToken(sessionToken);\n\n return sessionPayload.sessionId;\n } catch (error) {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport default getSessionId;\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,MAAM,eAAe,YAAyC;CAG5D,MAAMA,gBAF8B,iCAAe,EAEE,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEjG,KAAI,aACF,KAAI;AAGF,UAF4C,MAAMA,+BAAe,mBAAmB,aAAa,EAE3E;UACf,OAAO;AACd;;;AAON,2BAAe"}
1
+ {"version":3,"file":"getSessionId.cjs","names":["sessionToken: string | undefined","SessionManager"],"sources":["../../../../src/server/actions/getSessionId.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Get the session ID from cookies.\n * Tries JWT session first, then falls back to legacy session ID.\n *\n * @returns The session ID if it exists, undefined otherwise\n */\nconst getSessionId = async (): Promise<string | undefined> => {\n const cookieStore: RequestCookies = await cookies();\n\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (sessionToken) {\n try {\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionToken(sessionToken);\n\n return sessionPayload.sessionId;\n } catch (error) {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport default getSessionId;\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAM,eAAe,YAAyC;CAG5D,MAAMA,gBAF8B,iCAAe,EAEE,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEjG,KAAI,aACF,KAAI;AAGF,UAF4C,MAAMA,+BAAe,mBAAmB,aAAa,EAE3E;UACf,OAAO;AACd;;;AAON,2BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getSessionPayload.cjs","names":["sessionToken: string | undefined","SessionManager"],"sources":["../../../../src/server/actions/getSessionPayload.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Get the session payload from JWT session cookie.\n * This includes user ID, session ID, scopes, and organization ID.\n *\n * @returns The session payload if valid JWT session exists, undefined otherwise\n */\nconst getSessionPayload = async (): Promise<SessionTokenPayload | undefined> => {\n const cookieStore: RequestCookies = await cookies();\n\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n if (!sessionToken) {\n return undefined;\n }\n\n try {\n return await SessionManager.verifySessionToken(sessionToken);\n } catch {\n return undefined;\n }\n};\n\nexport default getSessionPayload;\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,MAAM,oBAAoB,YAAsD;CAG9E,MAAMA,gBAF8B,iCAAe,EAEE,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AACjG,KAAI,CAAC,aACH;AAGF,KAAI;AACF,SAAO,MAAMA,+BAAe,mBAAmB,aAAa;SACtD;AACN;;;AAIJ,gCAAe"}
1
+ {"version":3,"file":"getSessionPayload.cjs","names":["sessionToken: string | undefined","SessionManager"],"sources":["../../../../src/server/actions/getSessionPayload.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Get the session payload from JWT session cookie.\n * This includes user ID, session ID, scopes, and organization ID.\n *\n * @returns The session payload if valid JWT session exists, undefined otherwise\n */\nconst getSessionPayload = async (): Promise<SessionTokenPayload | undefined> => {\n const cookieStore: RequestCookies = await cookies();\n\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n if (!sessionToken) {\n return undefined;\n }\n\n try {\n return await SessionManager.verifySessionToken(sessionToken);\n } catch {\n return undefined;\n }\n};\n\nexport default getSessionPayload;\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAM,oBAAoB,YAAsD;CAG9E,MAAMA,gBAF8B,iCAAe,EAEE,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AACjG,KAAI,CAAC,aACH;AAGF,KAAI;AACF,SAAO,MAAMA,+BAAe,mBAAmB,aAAa;SACtD;AACN;;;AAIJ,gCAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getUserAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/getUserAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {User} from '@thunderid/node';\nimport getClient from '../getClient';\n\n/**\n * Server action to get the current user.\n * Returns the user profile if signed in.\n */\nconst getUserAction = async (\n sessionId: string,\n): Promise<{data: {user: User | null}; error: string | null; success: boolean}> => {\n try {\n const client = getClient();\n const user: User = await client.getUser(sessionId);\n return {data: {user}, error: null, success: true};\n } catch (error) {\n return {data: {user: null}, error: 'Failed to get user', success: false};\n }\n};\n\nexport default getUserAction;\n"],"mappings":";;;;;;;;;;AA2BA,MAAM,gBAAgB,OACpB,cACiF;AACjF,KAAI;AAGF,SAAO;GAAC,MAAM,EAAC,MADI,MADJA,2BAAW,CACM,QAAQ,UAAU,EAC9B;GAAE,OAAO;GAAM,SAAS;GAAK;UAC1C,OAAO;AACd,SAAO;GAAC,MAAM,EAAC,MAAM,MAAK;GAAE,OAAO;GAAsB,SAAS;GAAM;;;AAI5E,4BAAe"}
1
+ {"version":3,"file":"getUserAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/getUserAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {User} from '@thunderid/node';\nimport getClient from '../getClient';\n\n/**\n * Server action to get the current user.\n * Returns the user profile if signed in.\n */\nconst getUserAction = async (\n sessionId: string,\n): Promise<{data: {user: User | null}; error: string | null; success: boolean}> => {\n try {\n const client = getClient();\n const user: User = await client.getUser(sessionId);\n return {data: {user}, error: null, success: true};\n } catch (error) {\n return {data: {user: null}, error: 'Failed to get user', success: false};\n }\n};\n\nexport default getUserAction;\n"],"mappings":";;;;;;;;;;AAYA,MAAM,gBAAgB,OACpB,cACiF;AACjF,KAAI;AAGF,SAAO;GAAC,MAAM,EAAC,MADI,MADJA,2BAAW,CACM,QAAQ,UAAU,EAC9B;GAAE,OAAO;GAAM,SAAS;GAAK;UAC1C,OAAO;AACd,SAAO;GAAC,MAAM,EAAC,MAAM,MAAK;GAAE,OAAO;GAAsB,SAAS;GAAM;;;AAI5E,4BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getUserProfileAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/getUserProfileAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {UserProfile} from '@thunderid/node';\nimport getClient from '../getClient';\n\n/**\n * Server action to get the current user.\n * Returns the user profile if signed in.\n */\nconst getUserProfileAction = async (\n sessionId: string,\n): Promise<{data: {userProfile: UserProfile}; error: string | null; success: boolean}> => {\n try {\n const client = getClient();\n const updatedProfile: UserProfile = await client.getUserProfile(sessionId);\n return {data: {userProfile: updatedProfile}, error: null, success: true};\n } catch (error) {\n return {\n data: {\n userProfile: {\n flattenedProfile: {},\n profile: {},\n },\n },\n error: 'Failed to get user profile',\n success: false,\n };\n }\n};\n\nexport default getUserProfileAction;\n"],"mappings":";;;;;;;;;;AA2BA,MAAM,uBAAuB,OAC3B,cACwF;AACxF,KAAI;AAGF,SAAO;GAAC,MAAM,EAAC,aADqB,MADrBA,2BAAW,CACuB,eAAe,UAAU,EAC/B;GAAE,OAAO;GAAM,SAAS;GAAK;UACjE,OAAO;AACd,SAAO;GACL,MAAM,EACJ,aAAa;IACX,kBAAkB,EAAE;IACpB,SAAS,EAAE;IACZ,EACF;GACD,OAAO;GACP,SAAS;GACV;;;AAIL,mCAAe"}
1
+ {"version":3,"file":"getUserProfileAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/getUserProfileAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {UserProfile} from '@thunderid/node';\nimport getClient from '../getClient';\n\n/**\n * Server action to get the current user.\n * Returns the user profile if signed in.\n */\nconst getUserProfileAction = async (\n sessionId: string,\n): Promise<{data: {userProfile: UserProfile}; error: string | null; success: boolean}> => {\n try {\n const client = getClient();\n const updatedProfile: UserProfile = await client.getUserProfile(sessionId);\n return {data: {userProfile: updatedProfile}, error: null, success: true};\n } catch (error) {\n return {\n data: {\n userProfile: {\n flattenedProfile: {},\n profile: {},\n },\n },\n error: 'Failed to get user profile',\n success: false,\n };\n }\n};\n\nexport default getUserProfileAction;\n"],"mappings":";;;;;;;;;;AAYA,MAAM,uBAAuB,OAC3B,cACwF;AACxF,KAAI;AAGF,SAAO;GAAC,MAAM,EAAC,aADqB,MADrBA,2BAAW,CACuB,eAAe,UAAU,EAC/B;GAAE,OAAO;GAAM,SAAS;GAAK;UACjE,OAAO;AACd,SAAO;GACL,MAAM,EACJ,aAAa;IACX,kBAAkB,EAAE;IACpB,SAAS,EAAE;IACZ,EACF;GACD,OAAO;GACP,SAAS;GACV;;;AAIL,mCAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"handleOAuthCallbackAction.cjs","names":["getClient","cookieStore: RequestCookies","sessionId: string | undefined","tempSessionToken: string | undefined","SessionManager","signInResult: Record<string, unknown>","config: ThunderIDNextConfig","idToken: IdToken","accessToken: string","refreshToken: string","userIdFromToken: string","scopes: string","organizationId: string | undefined","expiresIn: number","sessionCookieExpiryTime: number","sessionToken: string"],"sources":["../../../../src/server/actions/handleOAuthCallbackAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {IdToken} from '@thunderid/node';\nimport {cookies} from 'next/headers';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport logger from '../../utils/logger';\nimport SessionManager from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Server action to handle OAuth callback with authorization code.\n * This action processes the authorization code received from the OAuth provider\n * and exchanges it for tokens to complete the authentication flow.\n *\n * @param code - Authorization code from OAuth provider\n * @param state - State parameter from OAuth provider for CSRF protection\n * @param sessionState - Session state parameter from OAuth provider\n * @returns Promise that resolves with success status and optional error message\n */\nconst handleOAuthCallbackAction = async (\n code: string,\n state: string,\n sessionState?: string,\n): Promise<{\n error?: string;\n redirectUrl?: string;\n success: boolean;\n}> => {\n try {\n if (!code || !state) {\n return {\n error: 'Missing required OAuth parameters: code and state are required',\n success: false,\n };\n }\n\n const thunderIDClient = getClient();\n\n if (!thunderIDClient.isInitialized) {\n return {\n error: 'ThunderID client is not initialized',\n success: false,\n };\n }\n\n const cookieStore: RequestCookies = await cookies();\n let sessionId: string | undefined;\n\n const tempSessionToken: string | undefined = cookieStore.get(SessionManager.getTempSessionCookieName())?.value;\n\n if (tempSessionToken) {\n try {\n const tempSession: {sessionId: string} = await SessionManager.verifyTempSession(tempSessionToken);\n sessionId = tempSession.sessionId;\n } catch {\n logger.error(\n '[handleOAuthCallbackAction] Invalid temporary session token, falling back to session ID from cookies.',\n );\n }\n }\n\n if (!sessionId) {\n logger.error('[handleOAuthCallbackAction] No session ID found in cookies or temporary session token.');\n\n return {\n error: 'No session found. Please start the authentication flow again.',\n success: false,\n };\n }\n\n // Exchange the authorization code for tokens\n const signInResult: Record<string, unknown> = await thunderIDClient.signIn(\n {\n code,\n session_state: sessionState,\n state,\n } as any,\n {},\n sessionId,\n );\n\n const config: ThunderIDNextConfig = await thunderIDClient.getConfiguration();\n\n if (signInResult) {\n try {\n const idToken: IdToken = await thunderIDClient.getDecodedIdToken(\n sessionId,\n (signInResult['id_token'] || signInResult['idToken']) as string,\n );\n const accessToken: string = (signInResult['accessToken'] || signInResult['access_token']) as string;\n const refreshToken: string = (signInResult['refreshToken'] as string | undefined) ?? '';\n const userIdFromToken: string = (idToken.sub || signInResult['sub'] || sessionId) as string;\n const scopes: string = signInResult['scope'] as string;\n const organizationId: string | undefined = (idToken['user_org'] || idToken['organization_id']) as\n | string\n | undefined;\n const expiresIn: number = signInResult['expiresIn'] as number;\n const sessionCookieExpiryTime: number = SessionManager.resolveSessionCookieExpiry(\n config.sessionCookie?.expiryTime,\n );\n\n const sessionToken: string = await SessionManager.createSessionToken(\n accessToken,\n userIdFromToken,\n sessionId,\n scopes,\n expiresIn,\n refreshToken,\n organizationId,\n );\n\n cookieStore.set(\n SessionManager.getSessionCookieName(),\n sessionToken,\n SessionManager.getSessionCookieOptions(sessionCookieExpiryTime),\n );\n\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n } catch (error) {\n logger.error(\n `[handleOAuthCallbackAction] Failed to create JWT session, continuing with legacy session:\n ${typeof error === 'string' ? error : JSON.stringify(error)}`,\n );\n }\n }\n\n const afterSignInUrl: string = config.afterSignInUrl || '/';\n\n return {\n redirectUrl: afterSignInUrl,\n success: true,\n };\n } catch (error) {\n let errorMessage = 'Authentication failed';\n\n if (error instanceof Error) {\n errorMessage = error.message;\n } else if (error && typeof error === 'object' && 'message' in error) {\n errorMessage = String((error as {message: unknown}).message);\n } else if (typeof error === 'string') {\n errorMessage = error;\n }\n\n return {\n error: errorMessage,\n success: false,\n };\n }\n};\n\nexport default handleOAuthCallbackAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuCA,MAAM,4BAA4B,OAChC,MACA,OACA,iBAKI;AACJ,KAAI;AACF,MAAI,CAAC,QAAQ,CAAC,MACZ,QAAO;GACL,OAAO;GACP,SAAS;GACV;EAGH,MAAM,kBAAkBA,2BAAW;AAEnC,MAAI,CAAC,gBAAgB,cACnB,QAAO;GACL,OAAO;GACP,SAAS;GACV;EAGH,MAAMC,cAA8B,iCAAe;EACnD,IAAIC;EAEJ,MAAMC,mBAAuC,YAAY,IAAIC,+BAAe,0BAA0B,CAAC,EAAE;AAEzG,MAAI,iBACF,KAAI;AAEF,gBADyC,MAAMA,+BAAe,kBAAkB,iBAAiB,EACzE;UAClB;AACN,0BAAO,MACL,wGACD;;AAIL,MAAI,CAAC,WAAW;AACd,0BAAO,MAAM,yFAAyF;AAEtG,UAAO;IACL,OAAO;IACP,SAAS;IACV;;EAIH,MAAMC,eAAwC,MAAM,gBAAgB,OAClE;GACE;GACA,eAAe;GACf;GACD,EACD,EAAE,EACF,UACD;EAED,MAAMC,SAA8B,MAAM,gBAAgB,kBAAkB;AAE5E,MAAI,aACF,KAAI;GACF,MAAMC,UAAmB,MAAM,gBAAgB,kBAC7C,WACC,aAAa,eAAe,aAAa,WAC3C;GACD,MAAMC,cAAuB,aAAa,kBAAkB,aAAa;GACzE,MAAMC,eAAwB,aAAa,mBAA0C;GACrF,MAAMC,kBAA2B,QAAQ,OAAO,aAAa,UAAU;GACvE,MAAMC,SAAiB,aAAa;GACpC,MAAMC,iBAAsC,QAAQ,eAAe,QAAQ;GAG3E,MAAMC,YAAoB,aAAa;GACvC,MAAMC,0BAAkCV,+BAAe,2BACrD,OAAO,eAAe,WACvB;GAED,MAAMW,eAAuB,MAAMX,+BAAe,mBAChD,aACA,iBACA,WACA,QACA,WACA,cACA,eACD;AAED,eAAY,IACVA,+BAAe,sBAAsB,EACrC,cACAA,+BAAe,wBAAwB,wBAAwB,CAChE;AAED,eAAY,OAAOA,+BAAe,0BAA0B,CAAC;WACtD,OAAO;AACd,0BAAO,MACL;YACE,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,MAAM,GAC5D;;AAML,SAAO;GACL,aAH6B,OAAO,kBAAkB;GAItD,SAAS;GACV;UACM,OAAO;EACd,IAAI,eAAe;AAEnB,MAAI,iBAAiB,MACnB,gBAAe,MAAM;WACZ,SAAS,OAAO,UAAU,YAAY,aAAa,MAC5D,gBAAe,OAAQ,MAA6B,QAAQ;WACnD,OAAO,UAAU,SAC1B,gBAAe;AAGjB,SAAO;GACL,OAAO;GACP,SAAS;GACV;;;AAIL,wCAAe"}
1
+ {"version":3,"file":"handleOAuthCallbackAction.cjs","names":["getClient","cookieStore: RequestCookies","sessionId: string | undefined","tempSessionToken: string | undefined","SessionManager","signInResult: Record<string, unknown>","config: ThunderIDNextConfig","idToken: IdToken","accessToken: string","refreshToken: string","userIdFromToken: string","scopes: string","organizationId: string | undefined","expiresIn: number","sessionCookieExpiryTime: number","sessionToken: string"],"sources":["../../../../src/server/actions/handleOAuthCallbackAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {IdToken} from '@thunderid/node';\nimport {cookies} from 'next/headers';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport logger from '../../utils/logger';\nimport SessionManager from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Server action to handle OAuth callback with authorization code.\n * This action processes the authorization code received from the OAuth provider\n * and exchanges it for tokens to complete the authentication flow.\n *\n * @param code - Authorization code from OAuth provider\n * @param state - State parameter from OAuth provider for CSRF protection\n * @param sessionState - Session state parameter from OAuth provider\n * @returns Promise that resolves with success status and optional error message\n */\nconst handleOAuthCallbackAction = async (\n code: string,\n state: string,\n sessionState?: string,\n): Promise<{\n error?: string;\n redirectUrl?: string;\n success: boolean;\n}> => {\n try {\n if (!code || !state) {\n return {\n error: 'Missing required OAuth parameters: code and state are required',\n success: false,\n };\n }\n\n const thunderIDClient = getClient();\n\n if (!thunderIDClient.isInitialized) {\n return {\n error: 'ThunderID client is not initialized',\n success: false,\n };\n }\n\n const cookieStore: RequestCookies = await cookies();\n let sessionId: string | undefined;\n\n const tempSessionToken: string | undefined = cookieStore.get(SessionManager.getTempSessionCookieName())?.value;\n\n if (tempSessionToken) {\n try {\n const tempSession: {sessionId: string} = await SessionManager.verifyTempSession(tempSessionToken);\n sessionId = tempSession.sessionId;\n } catch {\n logger.error(\n '[handleOAuthCallbackAction] Invalid temporary session token, falling back to session ID from cookies.',\n );\n }\n }\n\n if (!sessionId) {\n logger.error('[handleOAuthCallbackAction] No session ID found in cookies or temporary session token.');\n\n return {\n error: 'No session found. Please start the authentication flow again.',\n success: false,\n };\n }\n\n // Exchange the authorization code for tokens\n const signInResult: Record<string, unknown> = await thunderIDClient.signIn(\n {\n code,\n session_state: sessionState,\n state,\n } as any,\n {},\n sessionId,\n );\n\n const config: ThunderIDNextConfig = await thunderIDClient.getConfiguration();\n\n if (signInResult) {\n try {\n const idToken: IdToken = await thunderIDClient.getDecodedIdToken(\n sessionId,\n (signInResult['id_token'] || signInResult['idToken']) as string,\n );\n const accessToken: string = (signInResult['accessToken'] || signInResult['access_token']) as string;\n const refreshToken: string = (signInResult['refreshToken'] as string | undefined) ?? '';\n const userIdFromToken: string = (idToken.sub || signInResult['sub'] || sessionId) as string;\n const scopes: string = signInResult['scope'] as string;\n const organizationId: string | undefined = (idToken['user_org'] || idToken['organization_id']) as\n | string\n | undefined;\n const expiresIn: number = signInResult['expiresIn'] as number;\n const sessionCookieExpiryTime: number = SessionManager.resolveSessionCookieExpiry(\n config.sessionCookie?.expiryTime,\n );\n\n const sessionToken: string = await SessionManager.createSessionToken(\n accessToken,\n userIdFromToken,\n sessionId,\n scopes,\n expiresIn,\n refreshToken,\n organizationId,\n );\n\n cookieStore.set(\n SessionManager.getSessionCookieName(),\n sessionToken,\n SessionManager.getSessionCookieOptions(sessionCookieExpiryTime),\n );\n\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n } catch (error) {\n logger.error(\n `[handleOAuthCallbackAction] Failed to create JWT session, continuing with legacy session:\n ${typeof error === 'string' ? error : JSON.stringify(error)}`,\n );\n }\n }\n\n const afterSignInUrl: string = config.afterSignInUrl || '/';\n\n return {\n redirectUrl: afterSignInUrl,\n success: true,\n };\n } catch (error) {\n let errorMessage = 'Authentication failed';\n\n if (error instanceof Error) {\n errorMessage = error.message;\n } else if (error && typeof error === 'object' && 'message' in error) {\n errorMessage = String((error as {message: unknown}).message);\n } else if (typeof error === 'string') {\n errorMessage = error;\n }\n\n return {\n error: errorMessage,\n success: false,\n };\n }\n};\n\nexport default handleOAuthCallbackAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,4BAA4B,OAChC,MACA,OACA,iBAKI;AACJ,KAAI;AACF,MAAI,CAAC,QAAQ,CAAC,MACZ,QAAO;GACL,OAAO;GACP,SAAS;GACV;EAGH,MAAM,kBAAkBA,2BAAW;AAEnC,MAAI,CAAC,gBAAgB,cACnB,QAAO;GACL,OAAO;GACP,SAAS;GACV;EAGH,MAAMC,cAA8B,iCAAe;EACnD,IAAIC;EAEJ,MAAMC,mBAAuC,YAAY,IAAIC,+BAAe,0BAA0B,CAAC,EAAE;AAEzG,MAAI,iBACF,KAAI;AAEF,gBADyC,MAAMA,+BAAe,kBAAkB,iBAAiB,EACzE;UAClB;AACN,0BAAO,MACL,wGACD;;AAIL,MAAI,CAAC,WAAW;AACd,0BAAO,MAAM,yFAAyF;AAEtG,UAAO;IACL,OAAO;IACP,SAAS;IACV;;EAIH,MAAMC,eAAwC,MAAM,gBAAgB,OAClE;GACE;GACA,eAAe;GACf;GACD,EACD,EAAE,EACF,UACD;EAED,MAAMC,SAA8B,MAAM,gBAAgB,kBAAkB;AAE5E,MAAI,aACF,KAAI;GACF,MAAMC,UAAmB,MAAM,gBAAgB,kBAC7C,WACC,aAAa,eAAe,aAAa,WAC3C;GACD,MAAMC,cAAuB,aAAa,kBAAkB,aAAa;GACzE,MAAMC,eAAwB,aAAa,mBAA0C;GACrF,MAAMC,kBAA2B,QAAQ,OAAO,aAAa,UAAU;GACvE,MAAMC,SAAiB,aAAa;GACpC,MAAMC,iBAAsC,QAAQ,eAAe,QAAQ;GAG3E,MAAMC,YAAoB,aAAa;GACvC,MAAMC,0BAAkCV,+BAAe,2BACrD,OAAO,eAAe,WACvB;GAED,MAAMW,eAAuB,MAAMX,+BAAe,mBAChD,aACA,iBACA,WACA,QACA,WACA,cACA,eACD;AAED,eAAY,IACVA,+BAAe,sBAAsB,EACrC,cACAA,+BAAe,wBAAwB,wBAAwB,CAChE;AAED,eAAY,OAAOA,+BAAe,0BAA0B,CAAC;WACtD,OAAO;AACd,0BAAO,MACL;YACE,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,MAAM,GAC5D;;AAML,SAAO;GACL,aAH6B,OAAO,kBAAkB;GAItD,SAAS;GACV;UACM,OAAO;EACd,IAAI,eAAe;AAEnB,MAAI,iBAAiB,MACnB,gBAAe,MAAM;WACZ,SAAS,OAAO,UAAU,YAAY,aAAa,MAC5D,gBAAe,OAAQ,MAA6B,QAAQ;WACnD,OAAO,UAAU,SAC1B,gBAAe;AAGjB,SAAO;GACL,OAAO;GACP,SAAS;GACV;;;AAIL,wCAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"isSignedIn.cjs","names":["getSessionPayload","resolvedSessionId: string | undefined","getSessionId","getClient"],"sources":["../../../../src/server/actions/isSignedIn.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport getSessionId from './getSessionId';\nimport getSessionPayload from './getSessionPayload';\nimport {SessionTokenPayload} from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\n/**\n * Check if the user is currently signed in.\n *\n * For JWT-based sessions: the session JWT exp claim is now tied to the access\n * token expiry. A successful jwtVerify (inside getSessionPayload) already proves\n * exp > now, so no separate timestamp comparison is needed here.\n *\n * Falls back to the legacy SDK in-memory check when no JWT session cookie exists.\n *\n * @param sessionId - Optional session ID (used only for the legacy fallback path)\n * @returns True if the user is signed in with a valid, non-expired token\n */\nconst isSignedIn = async (sessionId?: string): Promise<boolean> => {\n try {\n const sessionPayload: SessionTokenPayload | undefined = await getSessionPayload();\n\n if (sessionPayload) {\n return true;\n }\n\n // No JWT session — fall back to the legacy SDK in-memory store check.\n const resolvedSessionId: string | undefined = sessionId || (await getSessionId());\n\n if (!resolvedSessionId) {\n return false;\n }\n\n const client = getClient();\n\n try {\n const accessToken: string = await client.getAccessToken(resolvedSessionId);\n return !!accessToken;\n } catch {\n return false;\n }\n } catch {\n return false;\n }\n};\n\nexport default isSignedIn;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqCA,MAAM,aAAa,OAAO,cAAyC;AACjE,KAAI;AAGF,MAFwD,MAAMA,mCAAmB,CAG/E,QAAO;EAIT,MAAMC,oBAAwC,aAAc,MAAMC,8BAAc;AAEhF,MAAI,CAAC,kBACH,QAAO;EAGT,MAAM,SAASC,2BAAW;AAE1B,MAAI;AAEF,UAAO,CAAC,CADoB,MAAM,OAAO,eAAe,kBAAkB;UAEpE;AACN,UAAO;;SAEH;AACN,SAAO;;;AAIX,yBAAe"}
1
+ {"version":3,"file":"isSignedIn.cjs","names":["getSessionPayload","resolvedSessionId: string | undefined","getSessionId","getClient"],"sources":["../../../../src/server/actions/isSignedIn.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport getSessionId from './getSessionId';\nimport getSessionPayload from './getSessionPayload';\nimport {SessionTokenPayload} from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\n/**\n * Check if the user is currently signed in.\n *\n * For JWT-based sessions: the session JWT exp claim is now tied to the access\n * token expiry. A successful jwtVerify (inside getSessionPayload) already proves\n * exp > now, so no separate timestamp comparison is needed here.\n *\n * Falls back to the legacy SDK in-memory check when no JWT session cookie exists.\n *\n * @param sessionId - Optional session ID (used only for the legacy fallback path)\n * @returns True if the user is signed in with a valid, non-expired token\n */\nconst isSignedIn = async (sessionId?: string): Promise<boolean> => {\n try {\n const sessionPayload: SessionTokenPayload | undefined = await getSessionPayload();\n\n if (sessionPayload) {\n return true;\n }\n\n // No JWT session — fall back to the legacy SDK in-memory store check.\n const resolvedSessionId: string | undefined = sessionId || (await getSessionId());\n\n if (!resolvedSessionId) {\n return false;\n }\n\n const client = getClient();\n\n try {\n const accessToken: string = await client.getAccessToken(resolvedSessionId);\n return !!accessToken;\n } catch {\n return false;\n }\n } catch {\n return false;\n }\n};\n\nexport default isSignedIn;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsBA,MAAM,aAAa,OAAO,cAAyC;AACjE,KAAI;AAGF,MAFwD,MAAMA,mCAAmB,CAG/E,QAAO;EAIT,MAAMC,oBAAwC,aAAc,MAAMC,8BAAc;AAEhF,MAAI,CAAC,kBACH,QAAO;EAGT,MAAM,SAASC,2BAAW;AAE1B,MAAI;AAEF,UAAO,CAAC,CADoB,MAAM,OAAO,eAAe,kBAAkB;UAEpE;AACN,UAAO;;SAEH;AACN,SAAO;;;AAIX,yBAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"refreshToken.cjs","names":["cookieStore: RequestCookies","sessionToken: string | undefined","SessionManager","ThunderIDAPIError","sessionPayload: SessionTokenPayload","config: ThunderIDNextConfig","getClient","result: HandleRefreshTokenResult","handleRefreshToken","rawExpiresIn: string | undefined","expiresInSeconds: number","expiresAt: number"],"sources":["../../../../src/server/actions/refreshToken.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {ThunderIDAPIError, logger} from '@thunderid/node';\nimport {cookies} from 'next/headers';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport handleRefreshToken, {HandleRefreshTokenResult} from '../../utils/handleRefreshToken';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Client-safe result of a token refresh.\n *\n * Intentionally omits accessToken, refreshToken, idToken, and scopes — those stay\n * server-side in the HttpOnly session cookie. Returning tokens from a Server Action\n * serializes them into browser memory, defeating the HttpOnly boundary and exposing\n * them to XSS, browser extensions, and error-tracking SDKs.\n *\n * `expiresAt` is epoch seconds for the new access token; the client uses it to\n * schedule the next refresh.\n */\nexport interface RefreshResult {\n expiresAt: number;\n}\n\n/**\n * Server action to refresh the access token using the stored refresh token.\n * Exchanges the refresh token for a new token set and updates the session cookie.\n *\n * Delegates the HTTP exchange to handleRefreshToken so the same logic is shared\n * with the middleware token refresh path.\n *\n * Called from the client side (e.g. ThunderIDClientProvider refreshOnMount) where\n * Next.js allows cookie mutation. When invoked during SSR rendering the cookie\n * write is silently skipped and a warning is logged.\n */\nconst refreshToken = async (): Promise<RefreshResult> => {\n try {\n const cookieStore: RequestCookies = await cookies();\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (!sessionToken) {\n throw new ThunderIDAPIError(\n 'No active session found. User must be signed in to refresh the token.',\n 'refreshToken-ServerActionError-002',\n 'nextjs',\n 401,\n );\n }\n\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionTokenForRefresh(sessionToken);\n const client = getClient();\n const config: ThunderIDNextConfig = await client.getConfiguration();\n\n const result: HandleRefreshTokenResult = await handleRefreshToken(sessionPayload, {\n baseUrl: config.baseUrl ?? '',\n clientId: config.clientId ?? '',\n clientSecret: config.clientSecret ?? '',\n sessionCookie: config.sessionCookie,\n });\n\n try {\n cookieStore.set(\n SessionManager.getSessionCookieName(),\n result.newSessionToken,\n SessionManager.getSessionCookieOptions(result.sessionCookieExpiryTime),\n );\n } catch {\n // cookies().set() is only permitted inside a Server Action invoked from the client\n // or a Route Handler. When this action is called during SSR rendering the write\n // is blocked by Next.js. The middleware refresh path handles that case instead.\n logger.warn('[refreshToken] Could not write session cookie — called from SSR rendering context.');\n }\n\n const rawExpiresIn: string | undefined = result.tokenResponse.expiresIn;\n const expiresInSeconds: number = parseInt(rawExpiresIn ?? '', 10);\n if (Number.isNaN(expiresInSeconds)) {\n throw new Error(`[refreshToken] Invalid expiresIn value received: ${rawExpiresIn}`);\n }\n const expiresAt: number = Math.floor(Date.now() / 1000) + expiresInSeconds;\n\n logger.debug('[refreshToken] Token refresh succeeded.');\n return {expiresAt};\n } catch (error) {\n // Clear the dead session cookie before throwing so the browser is not left\n // holding a stale credential. This is best-effort — if called from an SSR\n // rendering context Next.js blocks cookie mutation; the middleware cleanup\n // path covers that case on the next request.\n try {\n const cookieStore: RequestCookies = await cookies();\n cookieStore.delete(SessionManager.getSessionCookieName());\n logger.debug('[refreshToken] Cleared session cookie after refresh failure.');\n } catch {\n // Intentionally swallowed — middleware handles cleanup when mutation is blocked.\n }\n\n throw new ThunderIDAPIError(\n `Failed to refresh the session: ${error instanceof Error ? error.message : JSON.stringify(error)}`,\n 'refreshToken-ServerActionError-001',\n 'nextjs',\n error instanceof ThunderIDAPIError ? error.statusCode : undefined,\n );\n }\n};\n\nexport default refreshToken;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuDA,MAAM,eAAe,YAAoC;AACvD,KAAI;EACF,MAAMA,cAA8B,iCAAe;EACnD,MAAMC,eAAmC,YAAY,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEjG,MAAI,CAAC,aACH,OAAM,IAAIC,mCACR,yEACA,sCACA,UACA,IACD;EAGH,MAAMC,iBAAsC,MAAMF,+BAAe,6BAA6B,aAAa;EAE3G,MAAMG,SAA8B,MADrBC,2BAAW,CACuB,kBAAkB;EAEnE,MAAMC,SAAmC,MAAMC,mCAAmB,gBAAgB;GAChF,SAAS,OAAO,WAAW;GAC3B,UAAU,OAAO,YAAY;GAC7B,cAAc,OAAO,gBAAgB;GACrC,eAAe,OAAO;GACvB,CAAC;AAEF,MAAI;AACF,eAAY,IACVN,+BAAe,sBAAsB,EACrC,OAAO,iBACPA,+BAAe,wBAAwB,OAAO,wBAAwB,CACvE;UACK;AAIN,2BAAO,KAAK,qFAAqF;;EAGnG,MAAMO,eAAmC,OAAO,cAAc;EAC9D,MAAMC,mBAA2B,SAAS,gBAAgB,IAAI,GAAG;AACjE,MAAI,OAAO,MAAM,iBAAiB,CAChC,OAAM,IAAI,MAAM,oDAAoD,eAAe;EAErF,MAAMC,YAAoB,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,GAAG;AAE1D,0BAAO,MAAM,0CAA0C;AACvD,SAAO,EAAC,WAAU;UACX,OAAO;AAKd,MAAI;AAEF,IADoC,iCAAe,EACvC,OAAOT,+BAAe,sBAAsB,CAAC;AACzD,2BAAO,MAAM,+DAA+D;UACtE;AAIR,QAAM,IAAIC,mCACR,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,KAAK,UAAU,MAAM,IAChG,sCACA,UACA,iBAAiBA,qCAAoB,MAAM,aAAa,OACzD;;;AAIL,2BAAe"}
1
+ {"version":3,"file":"refreshToken.cjs","names":["cookieStore: RequestCookies","sessionToken: string | undefined","SessionManager","ThunderIDAPIError","sessionPayload: SessionTokenPayload","config: ThunderIDNextConfig","getClient","result: HandleRefreshTokenResult","handleRefreshToken","rawExpiresIn: string | undefined","expiresInSeconds: number","expiresAt: number"],"sources":["../../../../src/server/actions/refreshToken.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {ThunderIDAPIError, logger} from '@thunderid/node';\nimport {cookies} from 'next/headers';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport handleRefreshToken, {HandleRefreshTokenResult} from '../../utils/handleRefreshToken';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Client-safe result of a token refresh.\n *\n * Intentionally omits accessToken, refreshToken, idToken, and scopes — those stay\n * server-side in the HttpOnly session cookie. Returning tokens from a Server Action\n * serializes them into browser memory, defeating the HttpOnly boundary and exposing\n * them to XSS, browser extensions, and error-tracking SDKs.\n *\n * `expiresAt` is epoch seconds for the new access token; the client uses it to\n * schedule the next refresh.\n */\nexport interface RefreshResult {\n expiresAt: number;\n}\n\n/**\n * Server action to refresh the access token using the stored refresh token.\n * Exchanges the refresh token for a new token set and updates the session cookie.\n *\n * Delegates the HTTP exchange to handleRefreshToken so the same logic is shared\n * with the middleware token refresh path.\n *\n * Called from the client side (e.g. ThunderIDClientProvider refreshOnMount) where\n * Next.js allows cookie mutation. When invoked during SSR rendering the cookie\n * write is silently skipped and a warning is logged.\n */\nconst refreshToken = async (): Promise<RefreshResult> => {\n try {\n const cookieStore: RequestCookies = await cookies();\n const sessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (!sessionToken) {\n throw new ThunderIDAPIError(\n 'No active session found. User must be signed in to refresh the token.',\n 'refreshToken-ServerActionError-002',\n 'nextjs',\n 401,\n );\n }\n\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionTokenForRefresh(sessionToken);\n const client = getClient();\n const config: ThunderIDNextConfig = await client.getConfiguration();\n\n const result: HandleRefreshTokenResult = await handleRefreshToken(sessionPayload, {\n baseUrl: config.baseUrl ?? '',\n clientId: config.clientId ?? '',\n clientSecret: config.clientSecret ?? '',\n sessionCookie: config.sessionCookie,\n });\n\n try {\n cookieStore.set(\n SessionManager.getSessionCookieName(),\n result.newSessionToken,\n SessionManager.getSessionCookieOptions(result.sessionCookieExpiryTime),\n );\n } catch {\n // cookies().set() is only permitted inside a Server Action invoked from the client\n // or a Route Handler. When this action is called during SSR rendering the write\n // is blocked by Next.js. The middleware refresh path handles that case instead.\n logger.warn('[refreshToken] Could not write session cookie — called from SSR rendering context.');\n }\n\n const rawExpiresIn: string | undefined = result.tokenResponse.expiresIn;\n const expiresInSeconds: number = parseInt(rawExpiresIn ?? '', 10);\n if (Number.isNaN(expiresInSeconds)) {\n throw new Error(`[refreshToken] Invalid expiresIn value received: ${rawExpiresIn}`);\n }\n const expiresAt: number = Math.floor(Date.now() / 1000) + expiresInSeconds;\n\n logger.debug('[refreshToken] Token refresh succeeded.');\n return {expiresAt};\n } catch (error) {\n // Clear the dead session cookie before throwing so the browser is not left\n // holding a stale credential. This is best-effort — if called from an SSR\n // rendering context Next.js blocks cookie mutation; the middleware cleanup\n // path covers that case on the next request.\n try {\n const cookieStore: RequestCookies = await cookies();\n cookieStore.delete(SessionManager.getSessionCookieName());\n logger.debug('[refreshToken] Cleared session cookie after refresh failure.');\n } catch {\n // Intentionally swallowed — middleware handles cleanup when mutation is blocked.\n }\n\n throw new ThunderIDAPIError(\n `Failed to refresh the session: ${error instanceof Error ? error.message : JSON.stringify(error)}`,\n 'refreshToken-ServerActionError-001',\n 'nextjs',\n error instanceof ThunderIDAPIError ? error.statusCode : undefined,\n );\n }\n};\n\nexport default refreshToken;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAM,eAAe,YAAoC;AACvD,KAAI;EACF,MAAMA,cAA8B,iCAAe;EACnD,MAAMC,eAAmC,YAAY,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEjG,MAAI,CAAC,aACH,OAAM,IAAIC,mCACR,yEACA,sCACA,UACA,IACD;EAGH,MAAMC,iBAAsC,MAAMF,+BAAe,6BAA6B,aAAa;EAE3G,MAAMG,SAA8B,MADrBC,2BAAW,CACuB,kBAAkB;EAEnE,MAAMC,SAAmC,MAAMC,mCAAmB,gBAAgB;GAChF,SAAS,OAAO,WAAW;GAC3B,UAAU,OAAO,YAAY;GAC7B,cAAc,OAAO,gBAAgB;GACrC,eAAe,OAAO;GACvB,CAAC;AAEF,MAAI;AACF,eAAY,IACVN,+BAAe,sBAAsB,EACrC,OAAO,iBACPA,+BAAe,wBAAwB,OAAO,wBAAwB,CACvE;UACK;AAIN,2BAAO,KAAK,qFAAqF;;EAGnG,MAAMO,eAAmC,OAAO,cAAc;EAC9D,MAAMC,mBAA2B,SAAS,gBAAgB,IAAI,GAAG;AACjE,MAAI,OAAO,MAAM,iBAAiB,CAChC,OAAM,IAAI,MAAM,oDAAoD,eAAe;EAErF,MAAMC,YAAoB,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,GAAG;AAE1D,0BAAO,MAAM,0CAA0C;AACvD,SAAO,EAAC,WAAU;UACX,OAAO;AAKd,MAAI;AAEF,IADoC,iCAAe,EACvC,OAAOT,+BAAe,sBAAsB,CAAC;AACzD,2BAAO,MAAM,+DAA+D;UACtE;AAIR,QAAM,IAAIC,mCACR,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,KAAK,UAAU,MAAM,IAChG,sCACA,UACA,iBAAiBA,qCAAoB,MAAM,aAAa,OACzD;;;AAIL,2BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"signInAction.cjs","names":["getClient","cookieStore: RequestCookies","sessionId: string | undefined","existingSessionToken: string | undefined","SessionManager","tempSessionToken: string | undefined","tempSessionToken: string","defaultSignInUrl: string","response: any","EmbeddedSignInFlowStatus","idToken: IdToken","userIdFromToken: string","organizationId: string | undefined","scopes: string","iat: number","exp: number","expiresIn: number","config: ThunderIDNextConfig","sessionCookieExpiryTime: number","sessionToken: string","afterSignInUrl: string"],"sources":["../../../../src/server/actions/signInAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {\n generateSessionId,\n EmbeddedSignInFlowStatus,\n EmbeddedFlowExecuteRequestConfig,\n IdToken,\n isEmpty,\n} from '@thunderid/node';\nimport {cookies} from 'next/headers';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport logger from '../../utils/logger';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Server action for signing in a user.\n * Handles the embedded sign-in flow and manages session cookies.\n *\n * @param payload - The embedded sign-in flow payload\n * @param request - The embedded flow execute request config\n * @returns Promise that resolves when sign-in is complete\n */\nconst signInAction = async (\n payload?: any,\n request?: EmbeddedFlowExecuteRequestConfig,\n): Promise<{\n data?:\n | {\n afterSignInUrl?: string;\n signInUrl?: string;\n }\n | Record<string, unknown>;\n error?: string;\n success: boolean;\n}> => {\n try {\n const client = getClient();\n const cookieStore: RequestCookies = await cookies();\n\n let sessionId: string | undefined;\n\n const existingSessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (existingSessionToken) {\n try {\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionToken(existingSessionToken);\n sessionId = sessionPayload.sessionId;\n } catch {\n // Invalid session token, will create new temp session\n }\n }\n\n if (!sessionId) {\n const tempSessionToken: string | undefined = cookieStore.get(SessionManager.getTempSessionCookieName())?.value;\n\n if (tempSessionToken) {\n try {\n const tempSession: {sessionId: string} = await SessionManager.verifyTempSession(tempSessionToken);\n sessionId = tempSession.sessionId;\n } catch {\n // Invalid temp session, will create new one\n }\n }\n }\n\n if (!sessionId) {\n sessionId = generateSessionId();\n\n const tempSessionToken: string = await SessionManager.createTempSession(sessionId);\n\n cookieStore.set(\n SessionManager.getTempSessionCookieName(),\n tempSessionToken,\n SessionManager.getTempSessionCookieOptions(),\n );\n }\n\n // If no payload provided, redirect to sign-in URL for redirect-based sign-in.\n if (!payload || isEmpty(payload)) {\n const defaultSignInUrl: string = await client.getAuthorizeRequestUrl({}, sessionId);\n return {data: {signInUrl: String(defaultSignInUrl)}, success: true};\n }\n\n // Handle embedded sign-in flow\n const response: any = await client.signIn(payload, request!, sessionId);\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Complete) {\n // On the V2 platform, a completed embedded flow (without a preceding `/authorize` redirect,\n // i.e. no `authId`) returns a self-contained JWT `assertion` rather than an authorization\n // code to exchange. This mirrors how @thunderid/react and @thunderid/vue treat it: the\n // assertion is used directly as the bearer session token.\n if (!response.assertion) {\n throw new Error('[signInAction] Flow completed without an assertion.');\n }\n\n const idToken: IdToken = await client.getDecodedIdToken(sessionId, response.assertion);\n const userIdFromToken: string = (idToken.sub as string | undefined) ?? sessionId;\n const organizationId: string | undefined = (idToken['user_org'] || idToken['organization_id']) as\n | string\n | undefined;\n const scopes: string = (idToken['scope'] as string | undefined) ?? '';\n const iat: number = (idToken['iat'] as number | undefined) ?? Math.floor(Date.now() / 1000);\n const exp: number = (idToken['exp'] as number | undefined) ?? iat + 3600;\n const expiresIn: number = Math.max(exp - iat, 0);\n\n const config: ThunderIDNextConfig = await client.getConfiguration();\n const sessionCookieExpiryTime: number = SessionManager.resolveSessionCookieExpiry(\n config.sessionCookie?.expiryTime,\n );\n\n const sessionToken: string = await SessionManager.createSessionToken(\n response.assertion,\n userIdFromToken,\n sessionId,\n scopes,\n expiresIn,\n '',\n organizationId,\n );\n\n cookieStore.set(\n SessionManager.getSessionCookieName(),\n sessionToken,\n SessionManager.getSessionCookieOptions(sessionCookieExpiryTime),\n );\n\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n\n const afterSignInUrl: string = await (await client.getStorageManager()).getConfigDataParameter('afterSignInUrl');\n return {data: {afterSignInUrl: String(afterSignInUrl)}, success: true};\n }\n\n return {data: response as Record<string, unknown>, success: true};\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : typeof (error as any)?.message === 'string'\n ? (error as any).message\n : String(error);\n logger.error(`[signInAction] Error during sign-in: ${message}`);\n return {error: message, success: false};\n }\n};\n\nexport default signInAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2CA,MAAM,eAAe,OACnB,SACA,YAUI;AACJ,KAAI;EACF,MAAM,SAASA,2BAAW;EAC1B,MAAMC,cAA8B,iCAAe;EAEnD,IAAIC;EAEJ,MAAMC,uBAA2C,YAAY,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEzG,MAAI,qBACF,KAAI;AAEF,gBAD4C,MAAMA,+BAAe,mBAAmB,qBAAqB,EAC9E;UACrB;AAKV,MAAI,CAAC,WAAW;GACd,MAAMC,mBAAuC,YAAY,IAAID,+BAAe,0BAA0B,CAAC,EAAE;AAEzG,OAAI,iBACF,KAAI;AAEF,iBADyC,MAAMA,+BAAe,kBAAkB,iBAAiB,EACzE;WAClB;;AAMZ,MAAI,CAAC,WAAW;AACd,wDAA+B;GAE/B,MAAME,mBAA2B,MAAMF,+BAAe,kBAAkB,UAAU;AAElF,eAAY,IACVA,+BAAe,0BAA0B,EACzC,kBACAA,+BAAe,6BAA6B,CAC7C;;AAIH,MAAI,CAAC,yCAAmB,QAAQ,EAAE;GAChC,MAAMG,mBAA2B,MAAM,OAAO,uBAAuB,EAAE,EAAE,UAAU;AACnF,UAAO;IAAC,MAAM,EAAC,WAAW,OAAO,iBAAiB,EAAC;IAAE,SAAS;IAAK;;EAIrE,MAAMC,WAAgB,MAAM,OAAO,OAAO,SAAS,SAAU,UAAU;AAEvE,MAAI,SAAS,eAAeC,0CAAyB,UAAU;AAK7D,OAAI,CAAC,SAAS,UACZ,OAAM,IAAI,MAAM,sDAAsD;GAGxE,MAAMC,UAAmB,MAAM,OAAO,kBAAkB,WAAW,SAAS,UAAU;GACtF,MAAMC,kBAA2B,QAAQ,OAA8B;GACvE,MAAMC,iBAAsC,QAAQ,eAAe,QAAQ;GAG3E,MAAMC,SAAkB,QAAQ,YAAmC;GACnE,MAAMC,MAAe,QAAQ,UAAiC,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAC3F,MAAMC,MAAe,QAAQ,UAAiC,MAAM;GACpE,MAAMC,YAAoB,KAAK,IAAI,MAAM,KAAK,EAAE;GAEhD,MAAMC,SAA8B,MAAM,OAAO,kBAAkB;GACnE,MAAMC,0BAAkCd,+BAAe,2BACrD,OAAO,eAAe,WACvB;GAED,MAAMe,eAAuB,MAAMf,+BAAe,mBAChD,SAAS,WACT,iBACA,WACA,QACA,WACA,IACA,eACD;AAED,eAAY,IACVA,+BAAe,sBAAsB,EACrC,cACAA,+BAAe,wBAAwB,wBAAwB,CAChE;AAED,eAAY,OAAOA,+BAAe,0BAA0B,CAAC;GAE7D,MAAMgB,iBAAyB,OAAO,MAAM,OAAO,mBAAmB,EAAE,uBAAuB,iBAAiB;AAChH,UAAO;IAAC,MAAM,EAAC,gBAAgB,OAAO,eAAe,EAAC;IAAE,SAAS;IAAK;;AAGxE,SAAO;GAAC,MAAM;GAAqC,SAAS;GAAK;UAC1D,OAAO;EACd,MAAM,UACJ,iBAAiB,QACb,MAAM,UACN,OAAQ,OAAe,YAAY,WAChC,MAAc,UACf,OAAO,MAAM;AACrB,yBAAO,MAAM,wCAAwC,UAAU;AAC/D,SAAO;GAAC,OAAO;GAAS,SAAS;GAAM;;;AAI3C,2BAAe"}
1
+ {"version":3,"file":"signInAction.cjs","names":["getClient","cookieStore: RequestCookies","sessionId: string | undefined","existingSessionToken: string | undefined","SessionManager","tempSessionToken: string | undefined","tempSessionToken: string","defaultSignInUrl: string","response: any","EmbeddedSignInFlowStatus","idToken: IdToken","userIdFromToken: string","organizationId: string | undefined","scopes: string","iat: number","exp: number","expiresIn: number","config: ThunderIDNextConfig","sessionCookieExpiryTime: number","sessionToken: string","afterSignInUrl: string"],"sources":["../../../../src/server/actions/signInAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {\n generateSessionId,\n EmbeddedSignInFlowStatus,\n EmbeddedFlowExecuteRequestConfig,\n IdToken,\n isEmpty,\n} from '@thunderid/node';\nimport {cookies} from 'next/headers';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport logger from '../../utils/logger';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Server action for signing in a user.\n * Handles the embedded sign-in flow and manages session cookies.\n *\n * @param payload - The embedded sign-in flow payload\n * @param request - The embedded flow execute request config\n * @returns Promise that resolves when sign-in is complete\n */\nconst signInAction = async (\n payload?: any,\n request?: EmbeddedFlowExecuteRequestConfig,\n): Promise<{\n data?:\n | {\n afterSignInUrl?: string;\n signInUrl?: string;\n }\n | Record<string, unknown>;\n error?: string;\n success: boolean;\n}> => {\n try {\n const client = getClient();\n const cookieStore: RequestCookies = await cookies();\n\n let sessionId: string | undefined;\n\n const existingSessionToken: string | undefined = cookieStore.get(SessionManager.getSessionCookieName())?.value;\n\n if (existingSessionToken) {\n try {\n const sessionPayload: SessionTokenPayload = await SessionManager.verifySessionToken(existingSessionToken);\n sessionId = sessionPayload.sessionId;\n } catch {\n // Invalid session token, will create new temp session\n }\n }\n\n if (!sessionId) {\n const tempSessionToken: string | undefined = cookieStore.get(SessionManager.getTempSessionCookieName())?.value;\n\n if (tempSessionToken) {\n try {\n const tempSession: {sessionId: string} = await SessionManager.verifyTempSession(tempSessionToken);\n sessionId = tempSession.sessionId;\n } catch {\n // Invalid temp session, will create new one\n }\n }\n }\n\n if (!sessionId) {\n sessionId = generateSessionId();\n\n const tempSessionToken: string = await SessionManager.createTempSession(sessionId);\n\n cookieStore.set(\n SessionManager.getTempSessionCookieName(),\n tempSessionToken,\n SessionManager.getTempSessionCookieOptions(),\n );\n }\n\n // If no payload provided, redirect to sign-in URL for redirect-based sign-in.\n if (!payload || isEmpty(payload)) {\n const defaultSignInUrl: string = await client.getAuthorizeRequestUrl({}, sessionId);\n return {data: {signInUrl: String(defaultSignInUrl)}, success: true};\n }\n\n // Handle embedded sign-in flow\n const response: any = await client.signIn(payload, request!, sessionId);\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Complete) {\n // On the V2 platform, a completed embedded flow (without a preceding `/authorize` redirect,\n // i.e. no `authId`) returns a self-contained JWT `assertion` rather than an authorization\n // code to exchange. This mirrors how @thunderid/react and @thunderid/vue treat it: the\n // assertion is used directly as the bearer session token.\n if (!response.assertion) {\n throw new Error('[signInAction] Flow completed without an assertion.');\n }\n\n const idToken: IdToken = await client.getDecodedIdToken(sessionId, response.assertion);\n const userIdFromToken: string = (idToken.sub as string | undefined) ?? sessionId;\n const organizationId: string | undefined = (idToken['user_org'] || idToken['organization_id']) as\n | string\n | undefined;\n const scopes: string = (idToken['scope'] as string | undefined) ?? '';\n const iat: number = (idToken['iat'] as number | undefined) ?? Math.floor(Date.now() / 1000);\n const exp: number = (idToken['exp'] as number | undefined) ?? iat + 3600;\n const expiresIn: number = Math.max(exp - iat, 0);\n\n const config: ThunderIDNextConfig = await client.getConfiguration();\n const sessionCookieExpiryTime: number = SessionManager.resolveSessionCookieExpiry(\n config.sessionCookie?.expiryTime,\n );\n\n const sessionToken: string = await SessionManager.createSessionToken(\n response.assertion,\n userIdFromToken,\n sessionId,\n scopes,\n expiresIn,\n '',\n organizationId,\n );\n\n cookieStore.set(\n SessionManager.getSessionCookieName(),\n sessionToken,\n SessionManager.getSessionCookieOptions(sessionCookieExpiryTime),\n );\n\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n\n const afterSignInUrl: string = await (await client.getStorageManager()).getConfigDataParameter('afterSignInUrl');\n return {data: {afterSignInUrl: String(afterSignInUrl)}, success: true};\n }\n\n return {data: response as Record<string, unknown>, success: true};\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : typeof (error as any)?.message === 'string'\n ? (error as any).message\n : String(error);\n logger.error(`[signInAction] Error during sign-in: ${message}`);\n return {error: message, success: false};\n }\n};\n\nexport default signInAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4BA,MAAM,eAAe,OACnB,SACA,YAUI;AACJ,KAAI;EACF,MAAM,SAASA,2BAAW;EAC1B,MAAMC,cAA8B,iCAAe;EAEnD,IAAIC;EAEJ,MAAMC,uBAA2C,YAAY,IAAIC,+BAAe,sBAAsB,CAAC,EAAE;AAEzG,MAAI,qBACF,KAAI;AAEF,gBAD4C,MAAMA,+BAAe,mBAAmB,qBAAqB,EAC9E;UACrB;AAKV,MAAI,CAAC,WAAW;GACd,MAAMC,mBAAuC,YAAY,IAAID,+BAAe,0BAA0B,CAAC,EAAE;AAEzG,OAAI,iBACF,KAAI;AAEF,iBADyC,MAAMA,+BAAe,kBAAkB,iBAAiB,EACzE;WAClB;;AAMZ,MAAI,CAAC,WAAW;AACd,wDAA+B;GAE/B,MAAME,mBAA2B,MAAMF,+BAAe,kBAAkB,UAAU;AAElF,eAAY,IACVA,+BAAe,0BAA0B,EACzC,kBACAA,+BAAe,6BAA6B,CAC7C;;AAIH,MAAI,CAAC,yCAAmB,QAAQ,EAAE;GAChC,MAAMG,mBAA2B,MAAM,OAAO,uBAAuB,EAAE,EAAE,UAAU;AACnF,UAAO;IAAC,MAAM,EAAC,WAAW,OAAO,iBAAiB,EAAC;IAAE,SAAS;IAAK;;EAIrE,MAAMC,WAAgB,MAAM,OAAO,OAAO,SAAS,SAAU,UAAU;AAEvE,MAAI,SAAS,eAAeC,0CAAyB,UAAU;AAK7D,OAAI,CAAC,SAAS,UACZ,OAAM,IAAI,MAAM,sDAAsD;GAGxE,MAAMC,UAAmB,MAAM,OAAO,kBAAkB,WAAW,SAAS,UAAU;GACtF,MAAMC,kBAA2B,QAAQ,OAA8B;GACvE,MAAMC,iBAAsC,QAAQ,eAAe,QAAQ;GAG3E,MAAMC,SAAkB,QAAQ,YAAmC;GACnE,MAAMC,MAAe,QAAQ,UAAiC,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAC3F,MAAMC,MAAe,QAAQ,UAAiC,MAAM;GACpE,MAAMC,YAAoB,KAAK,IAAI,MAAM,KAAK,EAAE;GAEhD,MAAMC,SAA8B,MAAM,OAAO,kBAAkB;GACnE,MAAMC,0BAAkCd,+BAAe,2BACrD,OAAO,eAAe,WACvB;GAED,MAAMe,eAAuB,MAAMf,+BAAe,mBAChD,SAAS,WACT,iBACA,WACA,QACA,WACA,IACA,eACD;AAED,eAAY,IACVA,+BAAe,sBAAsB,EACrC,cACAA,+BAAe,wBAAwB,wBAAwB,CAChE;AAED,eAAY,OAAOA,+BAAe,0BAA0B,CAAC;GAE7D,MAAMgB,iBAAyB,OAAO,MAAM,OAAO,mBAAmB,EAAE,uBAAuB,iBAAiB;AAChH,UAAO;IAAC,MAAM,EAAC,gBAAgB,OAAO,eAAe,EAAC;IAAE,SAAS;IAAK;;AAGxE,SAAO;GAAC,MAAM;GAAqC,SAAS;GAAK;UAC1D,OAAO;EACd,MAAM,UACJ,iBAAiB,QACb,MAAM,UACN,OAAQ,OAAe,YAAY,WAChC,MAAc,UACf,OAAO,MAAM;AACrB,yBAAO,MAAM,wCAAwC,UAAU;AAC/D,SAAO;GAAC,OAAO;GAAS,SAAS;GAAM;;;AAI3C,2BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"signOutAction.cjs","names":["cookieStore: RequestCookies","SessionManager","getClient","sessionId: string | undefined","getSessionId","errorMessage: unknown"],"sources":["../../../../src/server/actions/signOutAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport getSessionId from './getSessionId';\nimport logger from '../../utils/logger';\nimport SessionManager from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Server action for signing out a user.\n * Clears both JWT and legacy session cookies.\n *\n * @returns Promise that resolves with success status and optional after sign-out URL\n */\nconst signOutAction = async (): Promise<{data?: {afterSignOutUrl?: string}; error?: unknown; success: boolean}> => {\n logger.debug('[signOutAction] Initiating sign out process from the server action.');\n\n const clearSessionCookies = async (): Promise<void> => {\n const cookieStore: RequestCookies = await cookies();\n\n cookieStore.delete(SessionManager.getSessionCookieName());\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n };\n\n try {\n const client = getClient();\n const sessionId: string | undefined = await getSessionId();\n\n let afterSignOutUrl = '/';\n\n if (sessionId) {\n logger.debug('[signOutAction] Session ID found, invoking the `signOut` to obtain the `afterSignOutUrl`.');\n\n afterSignOutUrl = await client.signOut({}, sessionId);\n }\n\n await clearSessionCookies();\n\n return {data: {afterSignOutUrl}, success: true};\n } catch (error) {\n logger.error('[signOutAction] Error during sign out from the server action:', error);\n\n logger.debug('[signOutAction] Clearing session cookies due to error as a fallback.');\n\n await clearSessionCookies();\n\n let errorMessage: unknown;\n if (typeof error === 'string') {\n errorMessage = error;\n } else if (error instanceof Error) {\n errorMessage = error.message;\n } else {\n errorMessage = JSON.stringify(error);\n }\n\n return {\n error: errorMessage,\n success: false,\n };\n }\n};\n\nexport default signOutAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkCA,MAAM,gBAAgB,YAA6F;AACjH,wBAAO,MAAM,sEAAsE;CAEnF,MAAM,sBAAsB,YAA2B;EACrD,MAAMA,cAA8B,iCAAe;AAEnD,cAAY,OAAOC,+BAAe,sBAAsB,CAAC;AACzD,cAAY,OAAOA,+BAAe,0BAA0B,CAAC;;AAG/D,KAAI;EACF,MAAM,SAASC,2BAAW;EAC1B,MAAMC,YAAgC,MAAMC,8BAAc;EAE1D,IAAI,kBAAkB;AAEtB,MAAI,WAAW;AACb,0BAAO,MAAM,4FAA4F;AAEzG,qBAAkB,MAAM,OAAO,QAAQ,EAAE,EAAE,UAAU;;AAGvD,QAAM,qBAAqB;AAE3B,SAAO;GAAC,MAAM,EAAC,iBAAgB;GAAE,SAAS;GAAK;UACxC,OAAO;AACd,yBAAO,MAAM,iEAAiE,MAAM;AAEpF,yBAAO,MAAM,uEAAuE;AAEpF,QAAM,qBAAqB;EAE3B,IAAIC;AACJ,MAAI,OAAO,UAAU,SACnB,gBAAe;WACN,iBAAiB,MAC1B,gBAAe,MAAM;MAErB,gBAAe,KAAK,UAAU,MAAM;AAGtC,SAAO;GACL,OAAO;GACP,SAAS;GACV;;;AAIL,4BAAe"}
1
+ {"version":3,"file":"signOutAction.cjs","names":["cookieStore: RequestCookies","SessionManager","getClient","sessionId: string | undefined","getSessionId","errorMessage: unknown"],"sources":["../../../../src/server/actions/signOutAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {cookies} from 'next/headers';\nimport getSessionId from './getSessionId';\nimport logger from '../../utils/logger';\nimport SessionManager from '../../utils/SessionManager';\nimport getClient from '../getClient';\n\ntype RequestCookies = Awaited<ReturnType<typeof cookies>>;\n\n/**\n * Server action for signing out a user.\n * Clears both JWT and legacy session cookies.\n *\n * @returns Promise that resolves with success status and optional after sign-out URL\n */\nconst signOutAction = async (): Promise<{data?: {afterSignOutUrl?: string}; error?: unknown; success: boolean}> => {\n logger.debug('[signOutAction] Initiating sign out process from the server action.');\n\n const clearSessionCookies = async (): Promise<void> => {\n const cookieStore: RequestCookies = await cookies();\n\n cookieStore.delete(SessionManager.getSessionCookieName());\n cookieStore.delete(SessionManager.getTempSessionCookieName());\n };\n\n try {\n const client = getClient();\n const sessionId: string | undefined = await getSessionId();\n\n let afterSignOutUrl = '/';\n\n if (sessionId) {\n logger.debug('[signOutAction] Session ID found, invoking the `signOut` to obtain the `afterSignOutUrl`.');\n\n afterSignOutUrl = await client.signOut({}, sessionId);\n }\n\n await clearSessionCookies();\n\n return {data: {afterSignOutUrl}, success: true};\n } catch (error) {\n logger.error('[signOutAction] Error during sign out from the server action:', error);\n\n logger.debug('[signOutAction] Clearing session cookies due to error as a fallback.');\n\n await clearSessionCookies();\n\n let errorMessage: unknown;\n if (typeof error === 'string') {\n errorMessage = error;\n } else if (error instanceof Error) {\n errorMessage = error.message;\n } else {\n errorMessage = JSON.stringify(error);\n }\n\n return {\n error: errorMessage,\n success: false,\n };\n }\n};\n\nexport default signOutAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,MAAM,gBAAgB,YAA6F;AACjH,wBAAO,MAAM,sEAAsE;CAEnF,MAAM,sBAAsB,YAA2B;EACrD,MAAMA,cAA8B,iCAAe;AAEnD,cAAY,OAAOC,+BAAe,sBAAsB,CAAC;AACzD,cAAY,OAAOA,+BAAe,0BAA0B,CAAC;;AAG/D,KAAI;EACF,MAAM,SAASC,2BAAW;EAC1B,MAAMC,YAAgC,MAAMC,8BAAc;EAE1D,IAAI,kBAAkB;AAEtB,MAAI,WAAW;AACb,0BAAO,MAAM,4FAA4F;AAEzG,qBAAkB,MAAM,OAAO,QAAQ,EAAE,EAAE,UAAU;;AAGvD,QAAM,qBAAqB;AAE3B,SAAO;GAAC,MAAM,EAAC,iBAAgB;GAAE,SAAS;GAAK;UACxC,OAAO;AACd,yBAAO,MAAM,iEAAiE,MAAM;AAEpF,yBAAO,MAAM,uEAAuE;AAEpF,QAAM,qBAAqB;EAE3B,IAAIC;AACJ,MAAI,OAAO,UAAU,SACnB,gBAAe;WACN,iBAAiB,MAC1B,gBAAe,MAAM;MAErB,gBAAe,KAAK,UAAU,MAAM;AAGtC,SAAO;GACL,OAAO;GACP,SAAS;GACV;;;AAIL,4BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"signUpAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/signUpAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport getClient from '../getClient';\n\n/**\n * Server action for initiating the sign-up redirect flow.\n */\nconst signUpAction = async (): Promise<{\n data?: {signUpUrl?: string};\n error?: string;\n success: boolean;\n}> => {\n try {\n const client = getClient();\n const config = client.getConfiguration() as any;\n const signUpUrl: string = config?.signUpUrl ?? '';\n\n return {data: {signUpUrl}, success: true};\n } catch (error) {\n return {error: String(error), success: false};\n }\n};\n\nexport default signUpAction;\n"],"mappings":";;;;;;;;;AAyBA,MAAM,eAAe,YAIf;AACJ,KAAI;AAKF,SAAO;GAAC,MAAM,EAAC,WAJAA,2BAAW,CACJ,kBAAkB,EACN,aAAa,IAEtB;GAAE,SAAS;GAAK;UAClC,OAAO;AACd,SAAO;GAAC,OAAO,OAAO,MAAM;GAAE,SAAS;GAAM;;;AAIjD,2BAAe"}
1
+ {"version":3,"file":"signUpAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/signUpAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport getClient from '../getClient';\n\n/**\n * Server action for initiating the sign-up redirect flow.\n */\nconst signUpAction = async (): Promise<{\n data?: {signUpUrl?: string};\n error?: string;\n success: boolean;\n}> => {\n try {\n const client = getClient();\n const config = client.getConfiguration() as any;\n const signUpUrl: string = config?.signUpUrl ?? '';\n\n return {data: {signUpUrl}, success: true};\n } catch (error) {\n return {error: String(error), success: false};\n }\n};\n\nexport default signUpAction;\n"],"mappings":";;;;;;;;;AAUA,MAAM,eAAe,YAIf;AACJ,KAAI;AAKF,SAAO;GAAC,MAAM,EAAC,WAJAA,2BAAW,CACJ,kBAAkB,EACN,aAAa,IAEtB;GAAE,SAAS;GAAK;UAClC,OAAO;AACd,SAAO;GAAC,OAAO,OAAO,MAAM;GAAE,SAAS;GAAM;;;AAIjD,2BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"updateUserProfileAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/updateUserProfileAction.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\n'use server';\n\nimport {UpdateMeProfileConfig, User} from '@thunderid/node';\nimport getClient from '../getClient';\n\n/**\n * Server action to get the current user.\n * Returns the user profile if signed in.\n */\nconst updateUserProfileAction = async (\n payload: UpdateMeProfileConfig,\n sessionId?: string,\n): Promise<{data: {user: User}; error: string; success: boolean}> => {\n try {\n const client = getClient();\n const user: User = await client.updateUserProfile(payload, sessionId);\n return {data: {user}, error: '', success: true};\n } catch (error) {\n return {\n data: {\n user: {},\n },\n error: `Failed to get user profile: ${error instanceof Error ? error.message : String(error)}`,\n success: false,\n };\n }\n};\n\nexport default updateUserProfileAction;\n"],"mappings":";;;;;;;;;;AA2BA,MAAM,0BAA0B,OAC9B,SACA,cACmE;AACnE,KAAI;AAGF,SAAO;GAAC,MAAM,EAAC,MADI,MADJA,2BAAW,CACM,kBAAkB,SAAS,UAAU,EACjD;GAAE,OAAO;GAAI,SAAS;GAAK;UACxC,OAAO;AACd,SAAO;GACL,MAAM,EACJ,MAAM,EAAE,EACT;GACD,OAAO,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC5F,SAAS;GACV;;;AAIL,sCAAe"}
1
+ {"version":3,"file":"updateUserProfileAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/updateUserProfileAction.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {UpdateMeProfileConfig, User} from '@thunderid/node';\nimport getClient from '../getClient';\n\n/**\n * Server action to get the current user.\n * Returns the user profile if signed in.\n */\nconst updateUserProfileAction = async (\n payload: UpdateMeProfileConfig,\n sessionId?: string,\n): Promise<{data: {user: User}; error: string; success: boolean}> => {\n try {\n const client = getClient();\n const user: User = await client.updateUserProfile(payload, sessionId);\n return {data: {user}, error: '', success: true};\n } catch (error) {\n return {\n data: {\n user: {},\n },\n error: `Failed to get user profile: ${error instanceof Error ? error.message : String(error)}`,\n success: false,\n };\n }\n};\n\nexport default updateUserProfileAction;\n"],"mappings":";;;;;;;;;;AAYA,MAAM,0BAA0B,OAC9B,SACA,cACmE;AACnE,KAAI;AAGF,SAAO;GAAC,MAAM,EAAC,MADI,MADJA,2BAAW,CACM,kBAAkB,SAAS,UAAU,EACjD;GAAE,OAAO;GAAI,SAAS;GAAK;UACxC,OAAO;AACd,SAAO;GACL,MAAM,EACJ,MAAM,EAAE,EACT;GACD,OAAO,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC5F,SAAS;GACV;;;AAIL,sCAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"getClient.cjs","names":["_instance: ThunderIDNextClient | undefined","ThunderIDNextClient"],"sources":["../../../src/server/getClient.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport ThunderIDNextClient from '../ThunderIDNextClient';\n\nlet _instance: ThunderIDNextClient | undefined;\n\n/**\n * Returns the shared `ThunderIDNextClient` instance for this Node.js process.\n * Creates a new instance on first call; subsequent calls return the same instance.\n *\n * @returns The shared ThunderIDNextClient instance.\n */\nconst getClient = (): ThunderIDNextClient => {\n if (!_instance) {\n _instance = new ThunderIDNextClient();\n }\n return _instance;\n};\n\nexport default getClient;\n"],"mappings":";;;AAoBA,IAAIA;;;;;;;AAQJ,MAAM,kBAAuC;AAC3C,KAAI,CAAC,UACH,aAAY,IAAIC,qCAAqB;AAEvC,QAAO;;AAGT,wBAAe"}
1
+ {"version":3,"file":"getClient.cjs","names":["_instance: ThunderIDNextClient | undefined","ThunderIDNextClient"],"sources":["../../../src/server/getClient.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport ThunderIDNextClient from '../ThunderIDNextClient';\n\nlet _instance: ThunderIDNextClient | undefined;\n\n/**\n * Returns the shared `ThunderIDNextClient` instance for this Node.js process.\n * Creates a new instance on first call; subsequent calls return the same instance.\n *\n * @returns The shared ThunderIDNextClient instance.\n */\nconst getClient = (): ThunderIDNextClient => {\n if (!_instance) {\n _instance = new ThunderIDNextClient();\n }\n return _instance;\n};\n\nexport default getClient;\n"],"mappings":";;;AAKA,IAAIA;;;;;;;AAQJ,MAAM,kBAAuC;AAC3C,KAAI,CAAC,UACH,aAAY,IAAIC,qCAAqB;AAEvC,QAAO;;AAGT,wBAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"createRouteMatcher.cjs","names":["regexPatterns: RegExp[]","regexPattern: string"],"sources":["../../../../src/server/proxy/createRouteMatcher.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport {NextRequest} from 'next/server';\n\n/**\n * Creates a route matcher function that tests if a request matches any of the given patterns.\n *\n * @param patterns - Array of route patterns to match. Supports glob-like patterns.\n * @returns Function that tests if a request matches any of the patterns\n *\n * @example\n * ```typescript\n * const isProtectedRoute = createRouteMatcher([\n * '/dashboard(.*)',\n * '/admin(.*)',\n * '/profile'\n * ]);\n *\n * if (isProtectedRoute(req)) {\n * // Route is protected\n * }\n * ```\n */\nconst createRouteMatcher = (patterns: string[]): ((req: NextRequest) => boolean) => {\n const regexPatterns: RegExp[] = patterns.map((pattern: string): RegExp => {\n // Convert glob-like patterns to regex\n const regexPattern: string = pattern\n .replace(/\\./g, '\\\\.') // Escape dots\n .replace(/\\*/g, '.*') // Convert * to .*\n .replace(/\\(\\.\\*\\)/g, '(.*)'); // Handle explicit (.*) patterns\n\n return new RegExp(`^${regexPattern}$`);\n });\n\n return (req: NextRequest): boolean => {\n const {pathname} = req.nextUrl;\n return regexPatterns.some((regex: RegExp): boolean => regex.test(pathname));\n };\n};\n\nexport default createRouteMatcher;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuCA,MAAM,sBAAsB,aAAwD;CAClF,MAAMA,gBAA0B,SAAS,KAAK,YAA4B;EAExE,MAAMC,eAAuB,QAC1B,QAAQ,OAAO,MAAM,CACrB,QAAQ,OAAO,KAAK,CACpB,QAAQ,aAAa,OAAO;AAE/B,yBAAO,IAAI,OAAO,IAAI,aAAa,GAAG;GACtC;AAEF,SAAQ,QAA8B;EACpC,MAAM,EAAC,aAAY,IAAI;AACvB,SAAO,cAAc,MAAM,UAA2B,MAAM,KAAK,SAAS,CAAC;;;AAI/E,iCAAe"}
1
+ {"version":3,"file":"createRouteMatcher.cjs","names":["regexPatterns: RegExp[]","regexPattern: string"],"sources":["../../../../src/server/proxy/createRouteMatcher.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {NextRequest} from 'next/server';\n\n/**\n * Creates a route matcher function that tests if a request matches any of the given patterns.\n *\n * @param patterns - Array of route patterns to match. Supports glob-like patterns.\n * @returns Function that tests if a request matches any of the patterns\n *\n * @example\n * ```typescript\n * const isProtectedRoute = createRouteMatcher([\n * '/dashboard(.*)',\n * '/admin(.*)',\n * '/profile'\n * ]);\n *\n * if (isProtectedRoute(req)) {\n * // Route is protected\n * }\n * ```\n */\nconst createRouteMatcher = (patterns: string[]): ((req: NextRequest) => boolean) => {\n const regexPatterns: RegExp[] = patterns.map((pattern: string): RegExp => {\n // Convert glob-like patterns to regex\n const regexPattern: string = pattern\n .replace(/\\./g, '\\\\.') // Escape dots\n .replace(/\\*/g, '.*') // Convert * to .*\n .replace(/\\(\\.\\*\\)/g, '(.*)'); // Handle explicit (.*) patterns\n\n return new RegExp(`^${regexPattern}$`);\n });\n\n return (req: NextRequest): boolean => {\n const {pathname} = req.nextUrl;\n return regexPatterns.some((regex: RegExp): boolean => regex.test(pathname));\n };\n};\n\nexport default createRouteMatcher;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,sBAAsB,aAAwD;CAClF,MAAMA,gBAA0B,SAAS,KAAK,YAA4B;EAExE,MAAMC,eAAuB,QAC1B,QAAQ,OAAO,MAAM,CACrB,QAAQ,OAAO,KAAK,CACpB,QAAQ,aAAa,OAAO;AAE/B,yBAAO,IAAI,OAAO,IAAI,aAAa,GAAG;GACtC;AAEF,SAAQ,QAA8B;EACpC,MAAM,EAAC,aAAY,IAAI;AACvB,SAAO,cAAc,MAAM,UAA2B,MAAM,KAAK,SAAS,CAAC;;;AAI/E,iCAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"thunderIDProxy.cjs","names":["eqIdx: number","parts: string[]","updated: string[]","resolvedConfig: ThunderIDNextConfig","decorateConfigWithNextEnv","url: URL","hasCallbackParams: boolean","tempSessionToken: string | undefined","SessionManager","verifiedSession: SessionTokenPayload | undefined","getSessionFromRequest","expiredSession: SessionTokenPayload | undefined","rawToken: string | undefined","decoded: SessionTokenPayload","now: number","candidateSession: SessionTokenPayload | undefined","needsRefresh: boolean","REFRESH_BUFFER_SECONDS","activeSession: SessionTokenPayload | undefined","refreshCookieUpdate: {expiry: number; token: string} | undefined","handleRefreshToken","rawSessionCookie: string | undefined","sessionId: string | undefined","getSessionIdFromRequest","handlerResponse: NextResponse | void","referer: string | null","refererUrl: URL","requestUrl: URL","redirectUrl: string","NextResponse","cookieName: string","cookieName","requestHeaders: Headers","cleanResponse: NextResponse","requestHeaders","cookieOptions: ReturnType<typeof SessionManager.getSessionCookieOptions>","updatedCookieHeader: string","response: NextResponse"],"sources":["../../../../src/server/proxy/thunderIDProxy.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport {NextRequest, NextResponse} from 'next/server';\nimport {REFRESH_BUFFER_SECONDS} from '../../constants/sessionConstants';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport decorateConfigWithNextEnv from '../../utils/decorateConfigWithNextEnv';\nimport handleRefreshToken from '../../utils/handleRefreshToken';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\nimport {getSessionFromRequest, getSessionIdFromRequest} from '../../utils/sessionUtils';\n\nexport type ThunderIDProxyOptions = Partial<ThunderIDNextConfig>;\n\nexport interface ThunderIDProxyContext {\n /** Get the session payload from JWT session if available */\n getSession: () => Promise<SessionTokenPayload | undefined>;\n /** Get the session ID from the current request */\n getSessionId: () => string | undefined;\n /** Check if the current request has a valid ThunderID session */\n isSignedIn: () => boolean;\n /**\n * Protect a route by redirecting unauthenticated users.\n * Redirect URL fallback order:\n * 1. options.redirect\n * 2. resolvedOptions.signInUrl\n * 3. resolvedOptions.defaultRedirect\n * 4. referer (if from same origin)\n * If none are available, falls back to '/'.\n */\n protectRoute: (routeOptions?: {redirect?: string}) => Promise<NextResponse | void>;\n}\n\ntype ThunderIDProxyHandler = (\n thunderid: ThunderIDProxyContext,\n req: NextRequest,\n) => Promise<NextResponse | void> | NextResponse | void;\n\n/**\n * Removes a named cookie from a raw Cookie header string.\n */\nconst removeCookieFromHeader = (cookieHeader: string, name: string): string =>\n cookieHeader\n .split(';')\n .map((p: string) => p.trim())\n .filter((p: string) => {\n const eqIdx: number = p.indexOf('=');\n const partName: string = eqIdx === -1 ? p : p.slice(0, eqIdx).trim();\n return partName !== name;\n })\n .join('; ');\n\n/**\n * Replaces the value of a named cookie inside a raw Cookie header string.\n * If the cookie does not already appear in the header it is appended.\n */\nconst replaceCookieInHeader = (cookieHeader: string, name: string, value: string): string => {\n const parts: string[] = cookieHeader\n .split(';')\n .map((p: string) => p.trim())\n .filter(Boolean);\n\n let found = false;\n const updated: string[] = parts.map((part: string) => {\n const eqIdx: number = part.indexOf('=');\n const partName: string = eqIdx === -1 ? part : part.slice(0, eqIdx).trim();\n if (partName === name) {\n found = true;\n return `${name}=${value}`;\n }\n return part;\n });\n\n if (!found) {\n updated.push(`${name}=${value}`);\n }\n\n return updated.join('; ');\n};\n\n/**\n * ThunderID proxy that integrates authentication into your Next.js application.\n * Similar to Clerk's clerkMiddleware pattern.\n *\n * Proactively refreshes the access token when it is within REFRESH_BUFFER_SECONDS of\n * expiry so that Server Components always receive a fresh session. The refresh also\n * recovers expired tokens as long as a refresh token is present.\n *\n * The updated session cookie is written to:\n * - The response → browser stores the new cookie for subsequent requests.\n * - The forwarded request headers → the same-request Server Component render sees\n * the fresh token immediately without waiting for the next navigation.\n *\n * Token refresh requires baseUrl, clientId, and clientSecret. These are resolved from\n * the options argument first, then from the standard ThunderID environment variables\n * (NEXT_PUBLIC_THUNDERID_BASE_URL, NEXT_PUBLIC_THUNDERID_CLIENT_ID,\n * THUNDERID_CLIENT_SECRET). If none are available the refresh step is skipped silently.\n *\n * @param handler - Optional handler function to customize proxy behavior\n * @param options - Configuration options for the proxy\n * @returns Next.js middleware function\n *\n * @example\n * ```typescript\n * // middleware.ts - Basic usage (config read from env vars automatically)\n * import { thunderIDProxy } from '@thunderid/nextjs/server';\n *\n * export default thunderIDProxy();\n *\n * export const config = {\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\n * };\n * ```\n *\n * @example\n * ```typescript\n * // With route protection\n * import { thunderIDProxy, createRouteMatcher } from '@thunderid/nextjs/server';\n *\n * const isProtectedRoute = createRouteMatcher(['/dashboard(.*)']);\n *\n * export default thunderIDProxy(async (thunderid, req) => {\n * if (isProtectedRoute(req)) {\n * await thunderid.protectRoute();\n * }\n * });\n * ```\n */\nconst thunderIDProxy =\n (\n handler?: ThunderIDProxyHandler,\n options?: ThunderIDProxyOptions | ((req: NextRequest) => ThunderIDProxyOptions),\n ): ((request: NextRequest) => Promise<NextResponse>) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const resolvedOptions: ThunderIDProxyOptions = typeof options === 'function' ? options(request) : options || {};\n\n // Resolve full config from passed options + environment variable fallbacks.\n const resolvedConfig: ThunderIDNextConfig = decorateConfigWithNextEnv(resolvedOptions as ThunderIDNextConfig);\n\n // ── OAuth callback detection ──────────────────────────────────────────────\n const url: URL = new URL(request.url);\n const hasCallbackParams: boolean = url.searchParams.has('code') && url.searchParams.has('state');\n\n let isValidOAuthCallback = false;\n if (hasCallbackParams && !url.searchParams.has('error')) {\n const tempSessionToken: string | undefined = request.cookies.get(\n SessionManager.getTempSessionCookieName(),\n )?.value;\n if (tempSessionToken) {\n try {\n await SessionManager.verifyTempSession(tempSessionToken);\n isValidOAuthCallback = true;\n } catch {\n isValidOAuthCallback = false;\n }\n }\n }\n\n // ── Session resolution ────────────────────────────────────────────────────\n // Step 1: Attempt to get a fully verified (signature + expiry) session.\n const verifiedSession: SessionTokenPayload | undefined = await getSessionFromRequest(request);\n\n // Step 2: If no verified session exists, verify the raw cookie's signature\n // without enforcing expiry. This allows the proxy to recover from an\n // expired access token as long as the JWT is authentic and a refresh token\n // is present. Skipping the signature check here would let a tampered cookie\n // drive identity-confusion attacks since handleRefreshToken reuses `sub`,\n // `sessionId`, and `organizationId` from the input payload when minting the\n // new session JWT.\n let expiredSession: SessionTokenPayload | undefined;\n if (!verifiedSession) {\n const rawToken: string | undefined = request.cookies.get(SessionManager.getSessionCookieName())?.value;\n if (rawToken) {\n try {\n const decoded: SessionTokenPayload = await SessionManager.verifySessionTokenForRefresh(rawToken);\n if (decoded.refreshToken) {\n expiredSession = decoded;\n }\n } catch {\n // Forged, tampered, wrong type, or malformed — ignore.\n }\n }\n }\n\n // ── Token refresh ─────────────────────────────────────────────────────────\n const now: number = Math.floor(Date.now() / 1000);\n const candidateSession: SessionTokenPayload | undefined = verifiedSession ?? expiredSession;\n\n // Config is required to call the token endpoint.\n const hasRefreshConfig = !!(resolvedConfig.baseUrl && resolvedConfig.clientId && resolvedConfig.clientSecret);\n\n // Refresh when:\n // a) Token is verified but within the proactive buffer window, OR\n // b) Token has already expired but a refresh token is available.\n const needsRefresh: boolean =\n !isValidOAuthCallback &&\n hasRefreshConfig &&\n !!candidateSession?.refreshToken &&\n ((!!verifiedSession && verifiedSession.exp <= now + REFRESH_BUFFER_SECONDS) || !!expiredSession);\n\n let activeSession: SessionTokenPayload | undefined = verifiedSession;\n let refreshCookieUpdate: {expiry: number; token: string} | undefined;\n\n if (needsRefresh && candidateSession) {\n try {\n const {newSessionToken, sessionCookieExpiryTime} = await handleRefreshToken(candidateSession, {\n baseUrl: resolvedConfig.baseUrl!,\n clientId: resolvedConfig.clientId!,\n clientSecret: resolvedConfig.clientSecret!,\n sessionCookie: resolvedConfig.sessionCookie,\n });\n // Verify the newly minted token so activeSession reflects fresh claims.\n activeSession = await SessionManager.verifySessionToken(newSessionToken);\n refreshCookieUpdate = {expiry: sessionCookieExpiryTime, token: newSessionToken};\n } catch {\n // Refresh failed — clear the irrecoverable session.\n activeSession = undefined;\n }\n }\n\n // ── Session cleanup detection ─────────────────────────────────────────────\n // Mark stale cookies for deletion when the session is irrecoverable. Skipped\n // during OAuth callbacks where a session cookie may not exist yet.\n const rawSessionCookie: string | undefined = request.cookies.get(SessionManager.getSessionCookieName())?.value;\n\n let shouldClearCookie = false;\n\n if (!isValidOAuthCallback && rawSessionCookie && !activeSession && !refreshCookieUpdate) {\n // A cookie was present but all resolution paths (verify, decode, refresh)\n // failed — the session is dead and cannot be recovered.\n shouldClearCookie = true;\n }\n\n const sessionId: string | undefined = activeSession?.sessionId ?? (await getSessionIdFromRequest(request));\n const isAuthenticated = !!activeSession;\n\n // ── Proxy context ─────────────────────────────────────────────────────────\n const thunderid: ThunderIDProxyContext = {\n getSession: async (): Promise<SessionTokenPayload | undefined> => activeSession,\n getSessionId: (): string | undefined => sessionId,\n isSignedIn: (): boolean => isAuthenticated,\n protectRoute: async (routeOptions?: {redirect?: string}): Promise<NextResponse | void> => {\n // Skip during a valid OAuth callback to avoid redirecting before the\n // callback action has had a chance to complete.\n if (isValidOAuthCallback) {\n return undefined;\n }\n\n if (!isAuthenticated) {\n const referer: string | null = request.headers.get('referer');\n let fallbackRedirect = '/';\n\n if (referer) {\n try {\n const refererUrl: URL = new URL(referer);\n const requestUrl: URL = new URL(request.url);\n if (refererUrl.origin === requestUrl.origin) {\n fallbackRedirect = refererUrl.pathname + refererUrl.search;\n }\n } catch {\n // Invalid referer — ignore.\n }\n }\n\n const redirectUrl: string = routeOptions?.redirect ?? resolvedConfig.signInUrl! ?? fallbackRedirect;\n\n return NextResponse.redirect(new URL(redirectUrl, request.url));\n }\n\n return undefined;\n },\n };\n\n // ── Handler ───────────────────────────────────────────────────────────────\n const handlerResponse: NextResponse | void = handler ? await handler(thunderid, request) : undefined;\n\n // ── Build final response ──────────────────────────────────────────────────\n if (shouldClearCookie) {\n const cookieName: string = SessionManager.getSessionCookieName();\n\n if (handlerResponse) {\n // Handler returned a response (e.g. a redirect from protectRoute).\n // Attach the deletion so the browser discards the stale cookie.\n handlerResponse.cookies.delete(cookieName);\n return handlerResponse;\n }\n\n // Pass-through: strip the dead cookie from the forwarded request headers\n // so the same-request Server Component render sees no session at all.\n const requestHeaders: Headers = new Headers(request.headers);\n requestHeaders.set('cookie', removeCookieFromHeader(request.headers.get('cookie') ?? '', cookieName));\n const cleanResponse: NextResponse = NextResponse.next({request: {headers: requestHeaders}});\n cleanResponse.cookies.delete(cookieName);\n return cleanResponse;\n }\n\n if (!refreshCookieUpdate) {\n return handlerResponse ?? NextResponse.next();\n }\n\n // A token refresh occurred — the new session cookie must be applied to:\n // 1. The HTTP response so the browser stores the updated cookie.\n // 2. The forwarded request headers so the same-request Server Component\n // render reads the fresh session token instead of the expired one.\n const cookieName: string = SessionManager.getSessionCookieName();\n const cookieOptions: ReturnType<typeof SessionManager.getSessionCookieOptions> =\n SessionManager.getSessionCookieOptions(refreshCookieUpdate.expiry);\n\n if (handlerResponse) {\n // Handler returned a response (e.g. a redirect from protectRoute).\n // Attach the refresh cookie so the browser receives it even on redirects.\n handlerResponse.cookies.set(cookieName, refreshCookieUpdate.token, cookieOptions);\n return handlerResponse;\n }\n\n // Default pass-through: update both the response cookie and the request\n // Cookie header so the downstream Server Component render is not stale.\n const requestHeaders: Headers = new Headers(request.headers);\n const updatedCookieHeader: string = replaceCookieInHeader(\n request.headers.get('cookie') ?? '',\n cookieName,\n refreshCookieUpdate.token,\n );\n requestHeaders.set('cookie', updatedCookieHeader);\n\n const response: NextResponse = NextResponse.next({request: {headers: requestHeaders}});\n response.cookies.set(cookieName, refreshCookieUpdate.token, cookieOptions);\n return response;\n };\n\nexport default thunderIDProxy;\n"],"mappings":";;;;;;;;;;;;;AAuDA,MAAM,0BAA0B,cAAsB,SACpD,aACG,MAAM,IAAI,CACV,KAAK,MAAc,EAAE,MAAM,CAAC,CAC5B,QAAQ,MAAc;CACrB,MAAMA,QAAgB,EAAE,QAAQ,IAAI;AAEpC,SADyB,UAAU,KAAK,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,MAChD;EACpB,CACD,KAAK,KAAK;;;;;AAMf,MAAM,yBAAyB,cAAsB,MAAc,UAA0B;CAC3F,MAAMC,QAAkB,aACrB,MAAM,IAAI,CACV,KAAK,MAAc,EAAE,MAAM,CAAC,CAC5B,OAAO,QAAQ;CAElB,IAAI,QAAQ;CACZ,MAAMC,UAAoB,MAAM,KAAK,SAAiB;EACpD,MAAMF,QAAgB,KAAK,QAAQ,IAAI;AAEvC,OADyB,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,MACzD,MAAM;AACrB,WAAQ;AACR,UAAO,GAAG,KAAK,GAAG;;AAEpB,SAAO;GACP;AAEF,KAAI,CAAC,MACH,SAAQ,KAAK,GAAG,KAAK,GAAG,QAAQ;AAGlC,QAAO,QAAQ,KAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmD3B,MAAM,kBAEF,SACA,YAEF,OAAO,YAAgD;CAIrD,MAAMG,iBAAsCC,0CAHG,OAAO,YAAY,aAAa,QAAQ,QAAQ,GAAG,WAAW,EAAE,CAGF;CAG7G,MAAMC,MAAW,IAAI,IAAI,QAAQ,IAAI;CACrC,MAAMC,oBAA6B,IAAI,aAAa,IAAI,OAAO,IAAI,IAAI,aAAa,IAAI,QAAQ;CAEhG,IAAI,uBAAuB;AAC3B,KAAI,qBAAqB,CAAC,IAAI,aAAa,IAAI,QAAQ,EAAE;EACvD,MAAMC,mBAAuC,QAAQ,QAAQ,IAC3DC,+BAAe,0BAA0B,CAC1C,EAAE;AACH,MAAI,iBACF,KAAI;AACF,SAAMA,+BAAe,kBAAkB,iBAAiB;AACxD,0BAAuB;UACjB;AACN,0BAAuB;;;CAO7B,MAAMC,kBAAmD,MAAMC,2CAAsB,QAAQ;CAS7F,IAAIC;AACJ,KAAI,CAAC,iBAAiB;EACpB,MAAMC,WAA+B,QAAQ,QAAQ,IAAIJ,+BAAe,sBAAsB,CAAC,EAAE;AACjG,MAAI,SACF,KAAI;GACF,MAAMK,UAA+B,MAAML,+BAAe,6BAA6B,SAAS;AAChG,OAAI,QAAQ,aACV,kBAAiB;UAEb;;CAOZ,MAAMM,MAAc,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;CACjD,MAAMC,mBAAoD,mBAAmB;CAG7E,MAAM,mBAAmB,CAAC,EAAE,eAAe,WAAW,eAAe,YAAY,eAAe;CAKhG,MAAMC,eACJ,CAAC,wBACD,oBACA,CAAC,CAAC,kBAAkB,iBAClB,CAAC,CAAC,mBAAmB,gBAAgB,OAAO,MAAMC,mDAA2B,CAAC,CAAC;CAEnF,IAAIC,gBAAiD;CACrD,IAAIC;AAEJ,KAAI,gBAAgB,iBAClB,KAAI;EACF,MAAM,EAAC,iBAAiB,4BAA2B,MAAMC,mCAAmB,kBAAkB;GAC5F,SAAS,eAAe;GACxB,UAAU,eAAe;GACzB,cAAc,eAAe;GAC7B,eAAe,eAAe;GAC/B,CAAC;AAEF,kBAAgB,MAAMZ,+BAAe,mBAAmB,gBAAgB;AACxE,wBAAsB;GAAC,QAAQ;GAAyB,OAAO;GAAgB;SACzE;AAEN,kBAAgB;;CAOpB,MAAMa,mBAAuC,QAAQ,QAAQ,IAAIb,+BAAe,sBAAsB,CAAC,EAAE;CAEzG,IAAI,oBAAoB;AAExB,KAAI,CAAC,wBAAwB,oBAAoB,CAAC,iBAAiB,CAAC,oBAGlE,qBAAoB;CAGtB,MAAMc,YAAgC,eAAe,aAAc,MAAMC,6CAAwB,QAAQ;CACzG,MAAM,kBAAkB,CAAC,CAAC;CAwC1B,MAAMC,kBAAuC,UAAU,MAAM,QArCpB;EACvC,YAAY,YAAsD;EAClE,oBAAwC;EACxC,kBAA2B;EAC3B,cAAc,OAAO,iBAAqE;AAGxF,OAAI,qBACF;AAGF,OAAI,CAAC,iBAAiB;IACpB,MAAMC,UAAyB,QAAQ,QAAQ,IAAI,UAAU;IAC7D,IAAI,mBAAmB;AAEvB,QAAI,QACF,KAAI;KACF,MAAMC,aAAkB,IAAI,IAAI,QAAQ;KACxC,MAAMC,aAAkB,IAAI,IAAI,QAAQ,IAAI;AAC5C,SAAI,WAAW,WAAW,WAAW,OACnC,oBAAmB,WAAW,WAAW,WAAW;YAEhD;IAKV,MAAMC,cAAsB,cAAc,YAAY,eAAe,aAAc;AAEnF,WAAOC,yBAAa,SAAS,IAAI,IAAI,aAAa,QAAQ,IAAI,CAAC;;;EAKpE,EAG+E,QAAQ,GAAG;AAG3F,KAAI,mBAAmB;EACrB,MAAMC,eAAqBtB,+BAAe,sBAAsB;AAEhE,MAAI,iBAAiB;AAGnB,mBAAgB,QAAQ,OAAOuB,aAAW;AAC1C,UAAO;;EAKT,MAAMC,mBAA0B,IAAI,QAAQ,QAAQ,QAAQ;AAC5D,mBAAe,IAAI,UAAU,uBAAuB,QAAQ,QAAQ,IAAI,SAAS,IAAI,IAAID,aAAW,CAAC;EACrG,MAAME,gBAA8BJ,yBAAa,KAAK,EAAC,SAAS,EAAC,SAASK,kBAAe,EAAC,CAAC;AAC3F,gBAAc,QAAQ,OAAOH,aAAW;AACxC,SAAO;;AAGT,KAAI,CAAC,oBACH,QAAO,mBAAmBF,yBAAa,MAAM;CAO/C,MAAMC,aAAqBtB,+BAAe,sBAAsB;CAChE,MAAM2B,gBACJ3B,+BAAe,wBAAwB,oBAAoB,OAAO;AAEpE,KAAI,iBAAiB;AAGnB,kBAAgB,QAAQ,IAAI,YAAY,oBAAoB,OAAO,cAAc;AACjF,SAAO;;CAKT,MAAMwB,iBAA0B,IAAI,QAAQ,QAAQ,QAAQ;CAC5D,MAAMI,sBAA8B,sBAClC,QAAQ,QAAQ,IAAI,SAAS,IAAI,IACjC,YACA,oBAAoB,MACrB;AACD,gBAAe,IAAI,UAAU,oBAAoB;CAEjD,MAAMC,WAAyBR,yBAAa,KAAK,EAAC,SAAS,EAAC,SAAS,gBAAe,EAAC,CAAC;AACtF,UAAS,QAAQ,IAAI,YAAY,oBAAoB,OAAO,cAAc;AAC1E,QAAO;;AAGX,6BAAe"}
1
+ {"version":3,"file":"thunderIDProxy.cjs","names":["eqIdx: number","parts: string[]","updated: string[]","resolvedConfig: ThunderIDNextConfig","decorateConfigWithNextEnv","url: URL","hasCallbackParams: boolean","tempSessionToken: string | undefined","SessionManager","verifiedSession: SessionTokenPayload | undefined","getSessionFromRequest","expiredSession: SessionTokenPayload | undefined","rawToken: string | undefined","decoded: SessionTokenPayload","now: number","candidateSession: SessionTokenPayload | undefined","needsRefresh: boolean","REFRESH_BUFFER_SECONDS","activeSession: SessionTokenPayload | undefined","refreshCookieUpdate: {expiry: number; token: string} | undefined","handleRefreshToken","rawSessionCookie: string | undefined","sessionId: string | undefined","getSessionIdFromRequest","handlerResponse: NextResponse | void","referer: string | null","refererUrl: URL","requestUrl: URL","redirectUrl: string","NextResponse","cookieName: string","cookieName","requestHeaders: Headers","cleanResponse: NextResponse","requestHeaders","cookieOptions: ReturnType<typeof SessionManager.getSessionCookieOptions>","updatedCookieHeader: string","response: NextResponse"],"sources":["../../../../src/server/proxy/thunderIDProxy.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {NextRequest, NextResponse} from 'next/server';\nimport {REFRESH_BUFFER_SECONDS} from '../../constants/sessionConstants';\nimport {ThunderIDNextConfig} from '../../models/config';\nimport decorateConfigWithNextEnv from '../../utils/decorateConfigWithNextEnv';\nimport handleRefreshToken from '../../utils/handleRefreshToken';\nimport SessionManager, {SessionTokenPayload} from '../../utils/SessionManager';\nimport {getSessionFromRequest, getSessionIdFromRequest} from '../../utils/sessionUtils';\n\nexport type ThunderIDProxyOptions = Partial<ThunderIDNextConfig>;\n\nexport interface ThunderIDProxyContext {\n /** Get the session payload from JWT session if available */\n getSession: () => Promise<SessionTokenPayload | undefined>;\n /** Get the session ID from the current request */\n getSessionId: () => string | undefined;\n /** Check if the current request has a valid ThunderID session */\n isSignedIn: () => boolean;\n /**\n * Protect a route by redirecting unauthenticated users.\n * Redirect URL fallback order:\n * 1. options.redirect\n * 2. resolvedOptions.signInUrl\n * 3. resolvedOptions.defaultRedirect\n * 4. referer (if from same origin)\n * If none are available, falls back to '/'.\n */\n protectRoute: (routeOptions?: {redirect?: string}) => Promise<NextResponse | void>;\n}\n\ntype ThunderIDProxyHandler = (\n thunderid: ThunderIDProxyContext,\n req: NextRequest,\n) => Promise<NextResponse | void> | NextResponse | void;\n\n/**\n * Removes a named cookie from a raw Cookie header string.\n */\nconst removeCookieFromHeader = (cookieHeader: string, name: string): string =>\n cookieHeader\n .split(';')\n .map((p: string) => p.trim())\n .filter((p: string) => {\n const eqIdx: number = p.indexOf('=');\n const partName: string = eqIdx === -1 ? p : p.slice(0, eqIdx).trim();\n return partName !== name;\n })\n .join('; ');\n\n/**\n * Replaces the value of a named cookie inside a raw Cookie header string.\n * If the cookie does not already appear in the header it is appended.\n */\nconst replaceCookieInHeader = (cookieHeader: string, name: string, value: string): string => {\n const parts: string[] = cookieHeader\n .split(';')\n .map((p: string) => p.trim())\n .filter(Boolean);\n\n let found = false;\n const updated: string[] = parts.map((part: string) => {\n const eqIdx: number = part.indexOf('=');\n const partName: string = eqIdx === -1 ? part : part.slice(0, eqIdx).trim();\n if (partName === name) {\n found = true;\n return `${name}=${value}`;\n }\n return part;\n });\n\n if (!found) {\n updated.push(`${name}=${value}`);\n }\n\n return updated.join('; ');\n};\n\n/**\n * ThunderID proxy that integrates authentication into your Next.js application.\n * Similar to Clerk's clerkMiddleware pattern.\n *\n * Proactively refreshes the access token when it is within REFRESH_BUFFER_SECONDS of\n * expiry so that Server Components always receive a fresh session. The refresh also\n * recovers expired tokens as long as a refresh token is present.\n *\n * The updated session cookie is written to:\n * - The response → browser stores the new cookie for subsequent requests.\n * - The forwarded request headers → the same-request Server Component render sees\n * the fresh token immediately without waiting for the next navigation.\n *\n * Token refresh requires baseUrl, clientId, and clientSecret. These are resolved from\n * the options argument first, then from the standard ThunderID environment variables\n * (NEXT_PUBLIC_THUNDERID_BASE_URL, NEXT_PUBLIC_THUNDERID_CLIENT_ID,\n * THUNDERID_CLIENT_SECRET). If none are available the refresh step is skipped silently.\n *\n * @param handler - Optional handler function to customize proxy behavior\n * @param options - Configuration options for the proxy\n * @returns Next.js middleware function\n *\n * @example\n * ```typescript\n * // middleware.ts - Basic usage (config read from env vars automatically)\n * import { thunderIDProxy } from '@thunderid/nextjs/server';\n *\n * export default thunderIDProxy();\n *\n * export const config = {\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\n * };\n * ```\n *\n * @example\n * ```typescript\n * // With route protection\n * import { thunderIDProxy, createRouteMatcher } from '@thunderid/nextjs/server';\n *\n * const isProtectedRoute = createRouteMatcher(['/dashboard(.*)']);\n *\n * export default thunderIDProxy(async (thunderid, req) => {\n * if (isProtectedRoute(req)) {\n * await thunderid.protectRoute();\n * }\n * });\n * ```\n */\nconst thunderIDProxy =\n (\n handler?: ThunderIDProxyHandler,\n options?: ThunderIDProxyOptions | ((req: NextRequest) => ThunderIDProxyOptions),\n ): ((request: NextRequest) => Promise<NextResponse>) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const resolvedOptions: ThunderIDProxyOptions = typeof options === 'function' ? options(request) : options || {};\n\n // Resolve full config from passed options + environment variable fallbacks.\n const resolvedConfig: ThunderIDNextConfig = decorateConfigWithNextEnv(resolvedOptions as ThunderIDNextConfig);\n\n // ── OAuth callback detection ──────────────────────────────────────────────\n const url: URL = new URL(request.url);\n const hasCallbackParams: boolean = url.searchParams.has('code') && url.searchParams.has('state');\n\n let isValidOAuthCallback = false;\n if (hasCallbackParams && !url.searchParams.has('error')) {\n const tempSessionToken: string | undefined = request.cookies.get(\n SessionManager.getTempSessionCookieName(),\n )?.value;\n if (tempSessionToken) {\n try {\n await SessionManager.verifyTempSession(tempSessionToken);\n isValidOAuthCallback = true;\n } catch {\n isValidOAuthCallback = false;\n }\n }\n }\n\n // ── Session resolution ────────────────────────────────────────────────────\n // Step 1: Attempt to get a fully verified (signature + expiry) session.\n const verifiedSession: SessionTokenPayload | undefined = await getSessionFromRequest(request);\n\n // Step 2: If no verified session exists, verify the raw cookie's signature\n // without enforcing expiry. This allows the proxy to recover from an\n // expired access token as long as the JWT is authentic and a refresh token\n // is present. Skipping the signature check here would let a tampered cookie\n // drive identity-confusion attacks since handleRefreshToken reuses `sub`,\n // `sessionId`, and `organizationId` from the input payload when minting the\n // new session JWT.\n let expiredSession: SessionTokenPayload | undefined;\n if (!verifiedSession) {\n const rawToken: string | undefined = request.cookies.get(SessionManager.getSessionCookieName())?.value;\n if (rawToken) {\n try {\n const decoded: SessionTokenPayload = await SessionManager.verifySessionTokenForRefresh(rawToken);\n if (decoded.refreshToken) {\n expiredSession = decoded;\n }\n } catch {\n // Forged, tampered, wrong type, or malformed — ignore.\n }\n }\n }\n\n // ── Token refresh ─────────────────────────────────────────────────────────\n const now: number = Math.floor(Date.now() / 1000);\n const candidateSession: SessionTokenPayload | undefined = verifiedSession ?? expiredSession;\n\n // Config is required to call the token endpoint.\n const hasRefreshConfig = !!(resolvedConfig.baseUrl && resolvedConfig.clientId && resolvedConfig.clientSecret);\n\n // Refresh when:\n // a) Token is verified but within the proactive buffer window, OR\n // b) Token has already expired but a refresh token is available.\n const needsRefresh: boolean =\n !isValidOAuthCallback &&\n hasRefreshConfig &&\n !!candidateSession?.refreshToken &&\n ((!!verifiedSession && verifiedSession.exp <= now + REFRESH_BUFFER_SECONDS) || !!expiredSession);\n\n let activeSession: SessionTokenPayload | undefined = verifiedSession;\n let refreshCookieUpdate: {expiry: number; token: string} | undefined;\n\n if (needsRefresh && candidateSession) {\n try {\n const {newSessionToken, sessionCookieExpiryTime} = await handleRefreshToken(candidateSession, {\n baseUrl: resolvedConfig.baseUrl!,\n clientId: resolvedConfig.clientId!,\n clientSecret: resolvedConfig.clientSecret!,\n sessionCookie: resolvedConfig.sessionCookie,\n });\n // Verify the newly minted token so activeSession reflects fresh claims.\n activeSession = await SessionManager.verifySessionToken(newSessionToken);\n refreshCookieUpdate = {expiry: sessionCookieExpiryTime, token: newSessionToken};\n } catch {\n // Refresh failed — clear the irrecoverable session.\n activeSession = undefined;\n }\n }\n\n // ── Session cleanup detection ─────────────────────────────────────────────\n // Mark stale cookies for deletion when the session is irrecoverable. Skipped\n // during OAuth callbacks where a session cookie may not exist yet.\n const rawSessionCookie: string | undefined = request.cookies.get(SessionManager.getSessionCookieName())?.value;\n\n let shouldClearCookie = false;\n\n if (!isValidOAuthCallback && rawSessionCookie && !activeSession && !refreshCookieUpdate) {\n // A cookie was present but all resolution paths (verify, decode, refresh)\n // failed — the session is dead and cannot be recovered.\n shouldClearCookie = true;\n }\n\n const sessionId: string | undefined = activeSession?.sessionId ?? (await getSessionIdFromRequest(request));\n const isAuthenticated = !!activeSession;\n\n // ── Proxy context ─────────────────────────────────────────────────────────\n const thunderid: ThunderIDProxyContext = {\n getSession: async (): Promise<SessionTokenPayload | undefined> => activeSession,\n getSessionId: (): string | undefined => sessionId,\n isSignedIn: (): boolean => isAuthenticated,\n protectRoute: async (routeOptions?: {redirect?: string}): Promise<NextResponse | void> => {\n // Skip during a valid OAuth callback to avoid redirecting before the\n // callback action has had a chance to complete.\n if (isValidOAuthCallback) {\n return undefined;\n }\n\n if (!isAuthenticated) {\n const referer: string | null = request.headers.get('referer');\n let fallbackRedirect = '/';\n\n if (referer) {\n try {\n const refererUrl: URL = new URL(referer);\n const requestUrl: URL = new URL(request.url);\n if (refererUrl.origin === requestUrl.origin) {\n fallbackRedirect = refererUrl.pathname + refererUrl.search;\n }\n } catch {\n // Invalid referer — ignore.\n }\n }\n\n const redirectUrl: string = routeOptions?.redirect ?? resolvedConfig.signInUrl! ?? fallbackRedirect;\n\n return NextResponse.redirect(new URL(redirectUrl, request.url));\n }\n\n return undefined;\n },\n };\n\n // ── Handler ───────────────────────────────────────────────────────────────\n const handlerResponse: NextResponse | void = handler ? await handler(thunderid, request) : undefined;\n\n // ── Build final response ──────────────────────────────────────────────────\n if (shouldClearCookie) {\n const cookieName: string = SessionManager.getSessionCookieName();\n\n if (handlerResponse) {\n // Handler returned a response (e.g. a redirect from protectRoute).\n // Attach the deletion so the browser discards the stale cookie.\n handlerResponse.cookies.delete(cookieName);\n return handlerResponse;\n }\n\n // Pass-through: strip the dead cookie from the forwarded request headers\n // so the same-request Server Component render sees no session at all.\n const requestHeaders: Headers = new Headers(request.headers);\n requestHeaders.set('cookie', removeCookieFromHeader(request.headers.get('cookie') ?? '', cookieName));\n const cleanResponse: NextResponse = NextResponse.next({request: {headers: requestHeaders}});\n cleanResponse.cookies.delete(cookieName);\n return cleanResponse;\n }\n\n if (!refreshCookieUpdate) {\n return handlerResponse ?? NextResponse.next();\n }\n\n // A token refresh occurred — the new session cookie must be applied to:\n // 1. The HTTP response so the browser stores the updated cookie.\n // 2. The forwarded request headers so the same-request Server Component\n // render reads the fresh session token instead of the expired one.\n const cookieName: string = SessionManager.getSessionCookieName();\n const cookieOptions: ReturnType<typeof SessionManager.getSessionCookieOptions> =\n SessionManager.getSessionCookieOptions(refreshCookieUpdate.expiry);\n\n if (handlerResponse) {\n // Handler returned a response (e.g. a redirect from protectRoute).\n // Attach the refresh cookie so the browser receives it even on redirects.\n handlerResponse.cookies.set(cookieName, refreshCookieUpdate.token, cookieOptions);\n return handlerResponse;\n }\n\n // Default pass-through: update both the response cookie and the request\n // Cookie header so the downstream Server Component render is not stale.\n const requestHeaders: Headers = new Headers(request.headers);\n const updatedCookieHeader: string = replaceCookieInHeader(\n request.headers.get('cookie') ?? '',\n cookieName,\n refreshCookieUpdate.token,\n );\n requestHeaders.set('cookie', updatedCookieHeader);\n\n const response: NextResponse = NextResponse.next({request: {headers: requestHeaders}});\n response.cookies.set(cookieName, refreshCookieUpdate.token, cookieOptions);\n return response;\n };\n\nexport default thunderIDProxy;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"thunderid.cjs","names":["getClient","getSessionIdAction"],"sources":["../../../src/server/thunderid.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport {TokenExchangeRequestConfig, TokenResponse} from '@thunderid/node';\nimport getSessionIdAction from './actions/getSessionId';\nimport getClient from './getClient';\nimport {ThunderIDNextConfig} from '../models/config';\n\nconst thunderid = async (): Promise<{\n exchangeToken: (config: TokenExchangeRequestConfig, sessionId: string) => Promise<TokenResponse | Response>;\n getAccessToken: (sessionId: string) => Promise<string>;\n getSessionId: () => Promise<string | undefined>;\n reInitialize: (config: Partial<ThunderIDNextConfig>) => Promise<boolean>;\n}> => {\n const getAccessToken = async (sessionId: string): Promise<string> => {\n const client = getClient();\n return client.getAccessToken(sessionId);\n };\n\n const getSessionId = async (): Promise<string | undefined> => getSessionIdAction();\n\n const exchangeToken = async (\n config: TokenExchangeRequestConfig,\n sessionId: string,\n ): Promise<TokenResponse | Response> => {\n const client = getClient();\n return client.exchangeToken(config, sessionId);\n };\n\n const reInitialize = async (config: Partial<ThunderIDNextConfig>): Promise<boolean> => {\n const client = getClient();\n return client.reInitialize(config);\n };\n\n return {\n exchangeToken,\n getAccessToken,\n getSessionId,\n reInitialize,\n };\n};\n\nexport default thunderid;\n"],"mappings":";;;;AAuBA,MAAM,YAAY,YAKZ;CACJ,MAAM,iBAAiB,OAAO,cAAuC;AAEnE,SADeA,2BAAW,CACZ,eAAe,UAAU;;CAGzC,MAAM,eAAe,YAAyCC,8BAAoB;CAElF,MAAM,gBAAgB,OACpB,QACA,cACsC;AAEtC,SADeD,2BAAW,CACZ,cAAc,QAAQ,UAAU;;CAGhD,MAAM,eAAe,OAAO,WAA2D;AAErF,SADeA,2BAAW,CACZ,aAAa,OAAO;;AAGpC,QAAO;EACL;EACA;EACA;EACA;EACD;;AAGH,wBAAe"}
1
+ {"version":3,"file":"thunderid.cjs","names":["getClient","getSessionIdAction"],"sources":["../../../src/server/thunderid.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {TokenExchangeRequestConfig, TokenResponse} from '@thunderid/node';\nimport getSessionIdAction from './actions/getSessionId';\nimport getClient from './getClient';\nimport {ThunderIDNextConfig} from '../models/config';\n\nconst thunderid = async (): Promise<{\n exchangeToken: (config: TokenExchangeRequestConfig, sessionId: string) => Promise<TokenResponse | Response>;\n getAccessToken: (sessionId: string) => Promise<string>;\n getSessionId: () => Promise<string | undefined>;\n reInitialize: (config: Partial<ThunderIDNextConfig>) => Promise<boolean>;\n}> => {\n const getAccessToken = async (sessionId: string): Promise<string> => {\n const client = getClient();\n return client.getAccessToken(sessionId);\n };\n\n const getSessionId = async (): Promise<string | undefined> => getSessionIdAction();\n\n const exchangeToken = async (\n config: TokenExchangeRequestConfig,\n sessionId: string,\n ): Promise<TokenResponse | Response> => {\n const client = getClient();\n return client.exchangeToken(config, sessionId);\n };\n\n const reInitialize = async (config: Partial<ThunderIDNextConfig>): Promise<boolean> => {\n const client = getClient();\n return client.reInitialize(config);\n };\n\n return {\n exchangeToken,\n getAccessToken,\n getSessionId,\n reInitialize,\n };\n};\n\nexport default thunderid;\n"],"mappings":";;;;AAQA,MAAM,YAAY,YAKZ;CACJ,MAAM,iBAAiB,OAAO,cAAuC;AAEnE,SADeA,2BAAW,CACZ,eAAe,UAAU;;CAGzC,MAAM,eAAe,YAAyCC,8BAAoB;CAElF,MAAM,gBAAgB,OACpB,QACA,cACsC;AAEtC,SADeD,2BAAW,CACZ,cAAc,QAAQ,UAAU;;CAGhD,MAAM,eAAe,OAAO,WAA2D;AAErF,SADeA,2BAAW,CACZ,aAAa,OAAO;;AAGpC,QAAO;EACL;EACA;EACA;EACA;EACD;;AAGH,wBAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.cjs","names":["secret: string | undefined","ThunderIDRuntimeError","secret: Uint8Array","SignJWT","envValue: string | undefined","parsed: number","DEFAULT_SESSION_COOKIE_EXPIRY_TIME","payload: SessionTokenPayload","CookieConfig"],"sources":["../../../src/utils/SessionManager.ts"],"sourcesContent":["/**\n * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).\n *\n * WSO2 LLC. licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except\n * in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport {ThunderIDRuntimeError, CookieConfig} from '@thunderid/node';\nimport {SignJWT, jwtVerify, compactVerify, JWTPayload} from 'jose';\nimport {DEFAULT_SESSION_COOKIE_EXPIRY_TIME} from '../constants/sessionConstants';\n\n/**\n * Session token payload interface\n */\nexport interface SessionTokenPayload extends JWTPayload {\n /** Expiration timestamp — doubles as the access token expiry (JWT exp == access token exp) */\n exp: number;\n /** Issued at timestamp */\n iat: number;\n /** Organization ID if applicable */\n organizationId?: string;\n /** The refresh token; empty string if not provided by the auth server */\n refreshToken: string;\n /** OAuth scopes */\n scopes: string[];\n /** Session ID */\n sessionId: string;\n /** User ID */\n sub: string;\n /** Token type discriminant — must be 'session' for access-session JWTs */\n type: 'session';\n}\n\n/**\n * Session management utility class for JWT-based session cookies\n */\nclass SessionManager {\n /**\n * Get the signing secret from environment variable\n * Throws error in production if not set\n */\n private static getSecret(): Uint8Array {\n const secret: string | undefined = process.env['THUNDERID_SECRET'];\n\n if (!secret) {\n if (process.env['NODE_ENV'] === 'production') {\n throw new ThunderIDRuntimeError(\n 'THUNDERID_SECRET environment variable is required in production',\n 'session-secret-required',\n 'nextjs',\n 'Set the THUNDERID_SECRET environment variable with a secure random string',\n );\n }\n // Use a default secret for development (not secure)\n // eslint-disable-next-line no-console\n console.warn('Using default secret for development. Set THUNDERID_SECRET for production!');\n return new TextEncoder().encode('development-secret-not-for-production');\n }\n\n return new TextEncoder().encode(secret);\n }\n\n /**\n * Create a temporary session cookie for login initiation\n */\n static async createTempSession(sessionId: string): Promise<string> {\n const secret: Uint8Array = this.getSecret();\n\n const jwt: string = await new SignJWT({\n sessionId,\n type: 'temp',\n })\n .setProtectedHeader({alg: 'HS256'})\n .setIssuedAt()\n .setExpirationTime('15m')\n .sign(secret);\n\n return jwt;\n }\n\n /**\n * Resolve the session cookie expiry time in seconds.\n *\n * Resolution order (first defined value wins):\n * 1. `configuredExpiry` — value from `ThunderIDNodeConfig.sessionCookie?.expiryTime`\n * 2. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME` environment variable\n * 3. `DEFAULT_SESSION_COOKIE_EXPIRY_TIME` (24 hours)\n */\n static resolveSessionCookieExpiry(configuredExpiry?: number): number {\n if (configuredExpiry != null && configuredExpiry > 0) {\n return configuredExpiry;\n }\n\n const envValue: string | undefined = process.env['THUNDERID_SESSION_COOKIE_EXPIRY_TIME'];\n\n if (envValue) {\n const parsed: number = parseInt(envValue, 10);\n\n if (!Number.isNaN(parsed) && parsed > 0) {\n return parsed;\n }\n }\n\n return DEFAULT_SESSION_COOKIE_EXPIRY_TIME;\n }\n\n static async createSessionToken(\n accessToken: string,\n userId: string,\n sessionId: string,\n scopes: string,\n accessTokenTtlSeconds: number,\n refreshToken: string,\n organizationId?: string,\n ): Promise<string> {\n const secret: Uint8Array = this.getSecret();\n\n const jwt: string = await new SignJWT({\n accessToken,\n organizationId,\n refreshToken,\n scopes,\n sessionId,\n type: 'session',\n } as Omit<SessionTokenPayload, 'sub' | 'iat' | 'exp'>)\n .setProtectedHeader({alg: 'HS256'})\n .setSubject(userId)\n .setIssuedAt()\n .setExpirationTime(Math.floor(Date.now() / 1000) + accessTokenTtlSeconds)\n .sign(secret);\n\n return jwt;\n }\n\n /**\n * Verify and decode a session token\n */\n static async verifySessionToken(token: string): Promise<SessionTokenPayload> {\n try {\n const secret: Uint8Array = this.getSecret();\n const {payload} = await jwtVerify(token, secret);\n\n if (payload['type'] !== 'session') {\n throw new Error('Invalid token type');\n }\n\n return payload as SessionTokenPayload;\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Invalid session token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'invalid-session-token',\n 'nextjs',\n 'Session token verification failed',\n );\n }\n }\n\n /**\n * Verify a session token for refresh. Validates the HMAC signature and the\n * `type === 'session'` discriminant but intentionally skips the `exp` check\n * so an expired access token can still be exchanged for a new one.\n *\n * Session lifetime is still bounded — the cookie's `maxAge` is set from\n * `sessionCookieExpiryTime`, so the browser drops an over-age session regardless\n * of the access-token exp embedded in the JWT.\n *\n * Never use the returned payload for authorization.\n */\n static async verifySessionTokenForRefresh(token: string): Promise<SessionTokenPayload> {\n try {\n const secret: Uint8Array = this.getSecret();\n const {payload: rawPayload} = await compactVerify(token, secret);\n const payload: SessionTokenPayload = JSON.parse(new TextDecoder().decode(rawPayload)) as SessionTokenPayload;\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type');\n }\n\n return payload;\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Invalid session token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'invalid-session-token-for-refresh',\n 'nextjs',\n 'Session token signature or type check failed during refresh',\n );\n }\n }\n\n /**\n * Verify and decode a temporary session token\n */\n static async verifyTempSession(token: string): Promise<{sessionId: string}> {\n try {\n const secret: Uint8Array = this.getSecret();\n const {payload} = await jwtVerify(token, secret);\n\n if (payload['type'] !== 'temp') {\n throw new Error('Invalid token type');\n }\n\n return {sessionId: payload['sessionId'] as string};\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Invalid temporary session token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'invalid-temp-session-token',\n 'nextjs',\n 'Temporary session token verification failed',\n );\n }\n }\n\n /**\n * Get session cookie options\n */\n static getSessionCookieOptions(maxAge: number): {\n httpOnly: boolean;\n maxAge: number;\n path: string;\n sameSite: 'lax';\n secure: boolean;\n } {\n return {\n httpOnly: true,\n maxAge,\n path: '/',\n sameSite: 'lax' as const,\n secure: process.env['NODE_ENV'] === 'production',\n };\n }\n\n /**\n * Get temporary session cookie options\n */\n static getTempSessionCookieOptions(): {\n httpOnly: boolean;\n maxAge: number;\n path: string;\n sameSite: 'lax';\n secure: boolean;\n } {\n return {\n httpOnly: true,\n maxAge: 15 * 60,\n path: '/',\n sameSite: 'lax' as const,\n secure: process.env['NODE_ENV'] === 'production',\n };\n }\n\n /**\n * Get session cookie name\n */\n static getSessionCookieName(): string {\n return CookieConfig.getSessionCookieName();\n }\n\n /**\n * Get temporary session cookie name\n */\n static getTempSessionCookieName(): string {\n return CookieConfig.getTempSessionCookieName();\n }\n}\n\nexport default SessionManager;\n"],"mappings":"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"}
1
+ {"version":3,"file":"SessionManager.cjs","names":["secret: string | undefined","ThunderIDRuntimeError","secret: Uint8Array","SignJWT","envValue: string | undefined","parsed: number","DEFAULT_SESSION_COOKIE_EXPIRY_TIME","payload: SessionTokenPayload","CookieConfig"],"sources":["../../../src/utils/SessionManager.ts"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {ThunderIDRuntimeError, CookieConfig} from '@thunderid/node';\nimport {SignJWT, jwtVerify, compactVerify, JWTPayload} from 'jose';\nimport {DEFAULT_SESSION_COOKIE_EXPIRY_TIME} from '../constants/sessionConstants';\n\n/**\n * Session token payload interface\n */\nexport interface SessionTokenPayload extends JWTPayload {\n /** Expiration timestamp — doubles as the access token expiry (JWT exp == access token exp) */\n exp: number;\n /** Issued at timestamp */\n iat: number;\n /** Organization ID if applicable */\n organizationId?: string;\n /** The refresh token; empty string if not provided by the auth server */\n refreshToken: string;\n /** OAuth scopes */\n scopes: string[];\n /** Session ID */\n sessionId: string;\n /** User ID */\n sub: string;\n /** Token type discriminant — must be 'session' for access-session JWTs */\n type: 'session';\n}\n\n/**\n * Session management utility class for JWT-based session cookies\n */\nclass SessionManager {\n /**\n * Get the signing secret from environment variable\n * Throws error in production if not set\n */\n private static getSecret(): Uint8Array {\n const secret: string | undefined = process.env['THUNDERID_SECRET'];\n\n if (!secret) {\n if (process.env['NODE_ENV'] === 'production') {\n throw new ThunderIDRuntimeError(\n 'THUNDERID_SECRET environment variable is required in production',\n 'session-secret-required',\n 'nextjs',\n 'Set the THUNDERID_SECRET environment variable with a secure random string',\n );\n }\n // Use a default secret for development (not secure)\n // eslint-disable-next-line no-console\n console.warn('Using default secret for development. Set THUNDERID_SECRET for production!');\n return new TextEncoder().encode('development-secret-not-for-production');\n }\n\n return new TextEncoder().encode(secret);\n }\n\n /**\n * Create a temporary session cookie for login initiation\n */\n static async createTempSession(sessionId: string): Promise<string> {\n const secret: Uint8Array = this.getSecret();\n\n const jwt: string = await new SignJWT({\n sessionId,\n type: 'temp',\n })\n .setProtectedHeader({alg: 'HS256'})\n .setIssuedAt()\n .setExpirationTime('15m')\n .sign(secret);\n\n return jwt;\n }\n\n /**\n * Resolve the session cookie expiry time in seconds.\n *\n * Resolution order (first defined value wins):\n * 1. `configuredExpiry` — value from `ThunderIDNodeConfig.sessionCookie?.expiryTime`\n * 2. `THUNDERID_SESSION_COOKIE_EXPIRY_TIME` environment variable\n * 3. `DEFAULT_SESSION_COOKIE_EXPIRY_TIME` (24 hours)\n */\n static resolveSessionCookieExpiry(configuredExpiry?: number): number {\n if (configuredExpiry != null && configuredExpiry > 0) {\n return configuredExpiry;\n }\n\n const envValue: string | undefined = process.env['THUNDERID_SESSION_COOKIE_EXPIRY_TIME'];\n\n if (envValue) {\n const parsed: number = parseInt(envValue, 10);\n\n if (!Number.isNaN(parsed) && parsed > 0) {\n return parsed;\n }\n }\n\n return DEFAULT_SESSION_COOKIE_EXPIRY_TIME;\n }\n\n static async createSessionToken(\n accessToken: string,\n userId: string,\n sessionId: string,\n scopes: string,\n accessTokenTtlSeconds: number,\n refreshToken: string,\n organizationId?: string,\n ): Promise<string> {\n const secret: Uint8Array = this.getSecret();\n\n const jwt: string = await new SignJWT({\n accessToken,\n organizationId,\n refreshToken,\n scopes,\n sessionId,\n type: 'session',\n } as Omit<SessionTokenPayload, 'sub' | 'iat' | 'exp'>)\n .setProtectedHeader({alg: 'HS256'})\n .setSubject(userId)\n .setIssuedAt()\n .setExpirationTime(Math.floor(Date.now() / 1000) + accessTokenTtlSeconds)\n .sign(secret);\n\n return jwt;\n }\n\n /**\n * Verify and decode a session token\n */\n static async verifySessionToken(token: string): Promise<SessionTokenPayload> {\n try {\n const secret: Uint8Array = this.getSecret();\n const {payload} = await jwtVerify(token, secret);\n\n if (payload['type'] !== 'session') {\n throw new Error('Invalid token type');\n }\n\n return payload as SessionTokenPayload;\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Invalid session token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'invalid-session-token',\n 'nextjs',\n 'Session token verification failed',\n );\n }\n }\n\n /**\n * Verify a session token for refresh. Validates the HMAC signature and the\n * `type === 'session'` discriminant but intentionally skips the `exp` check\n * so an expired access token can still be exchanged for a new one.\n *\n * Session lifetime is still bounded — the cookie's `maxAge` is set from\n * `sessionCookieExpiryTime`, so the browser drops an over-age session regardless\n * of the access-token exp embedded in the JWT.\n *\n * Never use the returned payload for authorization.\n */\n static async verifySessionTokenForRefresh(token: string): Promise<SessionTokenPayload> {\n try {\n const secret: Uint8Array = this.getSecret();\n const {payload: rawPayload} = await compactVerify(token, secret);\n const payload: SessionTokenPayload = JSON.parse(new TextDecoder().decode(rawPayload)) as SessionTokenPayload;\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type');\n }\n\n return payload;\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Invalid session token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'invalid-session-token-for-refresh',\n 'nextjs',\n 'Session token signature or type check failed during refresh',\n );\n }\n }\n\n /**\n * Verify and decode a temporary session token\n */\n static async verifyTempSession(token: string): Promise<{sessionId: string}> {\n try {\n const secret: Uint8Array = this.getSecret();\n const {payload} = await jwtVerify(token, secret);\n\n if (payload['type'] !== 'temp') {\n throw new Error('Invalid token type');\n }\n\n return {sessionId: payload['sessionId'] as string};\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Invalid temporary session token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'invalid-temp-session-token',\n 'nextjs',\n 'Temporary session token verification failed',\n );\n }\n }\n\n /**\n * Get session cookie options\n */\n static getSessionCookieOptions(maxAge: number): {\n httpOnly: boolean;\n maxAge: number;\n path: string;\n sameSite: 'lax';\n secure: boolean;\n } {\n return {\n httpOnly: true,\n maxAge,\n path: '/',\n sameSite: 'lax' as const,\n secure: process.env['NODE_ENV'] === 'production',\n };\n }\n\n /**\n * Get temporary session cookie options\n */\n static getTempSessionCookieOptions(): {\n httpOnly: boolean;\n maxAge: number;\n path: string;\n sameSite: 'lax';\n secure: boolean;\n } {\n return {\n httpOnly: true,\n maxAge: 15 * 60,\n path: '/',\n sameSite: 'lax' as const,\n secure: process.env['NODE_ENV'] === 'production',\n };\n }\n\n /**\n * Get session cookie name\n */\n static getSessionCookieName(): string {\n return CookieConfig.getSessionCookieName();\n }\n\n /**\n * Get temporary session cookie name\n */\n static getTempSessionCookieName(): string {\n return CookieConfig.getTempSessionCookieName();\n }\n}\n\nexport default SessionManager;\n"],"mappings":"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"}