@civic/auth 0.5.6-mcp-patch.2 → 0.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +36 -0
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +4 -33
- package/dist/nextjs/config.js.map +1 -1
- package/dist/nextjs/cookies.d.ts +4 -6
- package/dist/nextjs/cookies.d.ts.map +1 -1
- package/dist/nextjs/cookies.js +12 -20
- package/dist/nextjs/cookies.js.map +1 -1
- package/dist/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/nextjs/routeHandler.js +11 -5
- package/dist/nextjs/routeHandler.js.map +1 -1
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.d.ts.map +1 -1
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js +9 -1
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js.map +1 -1
- package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/server/ServerAuthenticationResolver.js +10 -8
- package/dist/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/services/AuthenticationService.d.ts +0 -1
- package/dist/services/AuthenticationService.d.ts.map +1 -1
- package/dist/services/AuthenticationService.js +19 -72
- package/dist/services/AuthenticationService.js.map +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.js +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/shared/components/IFrameAndLoading.d.ts.map +1 -1
- package/dist/shared/components/IFrameAndLoading.js +15 -1
- package/dist/shared/components/IFrameAndLoading.js.map +1 -1
- package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
- package/dist/shared/hooks/useSignIn.js +10 -13
- package/dist/shared/hooks/useSignIn.js.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.d.ts.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.js +3 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.js.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.js +9 -2
- package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/util.d.ts +2 -1
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +73 -30
- package/dist/shared/lib/util.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.d.ts.map +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/types.d.ts +7 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +18 -19
- package/dist/lib/cookies.d.ts +0 -7
- package/dist/lib/cookies.d.ts.map +0 -1
- package/dist/lib/cookies.js +0 -26
- package/dist/lib/cookies.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# 0.6.0 accessToken no longer pre-requisite for authenticated state
|
|
2
|
+
- Only a valid idToken is required in state for the user to be considered authenticated
|
|
3
|
+
- The refresh cookie for server-side token-exchange is now a session cookie, it will get deleted as part of the refresh flow if it's expired
|
|
4
|
+
|
|
1
5
|
# 0.5.5 loginSuccessUrl property
|
|
2
6
|
- Add a new setting for loginSuccessUrl in NextJS, redirecting the user to a page of the customer's choice after login
|
|
3
7
|
- Fix bug where logout would hang in modes other than iframe.
|
package/README.md
CHANGED
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
- [Express Example](#express-example)
|
|
37
37
|
- [Available Methods](#available-methods)
|
|
38
38
|
- [Server-Side Token Validation](#server-side-token-validation)
|
|
39
|
+
- [Authentication Storage and State](#authentication-storage-and-state)
|
|
40
|
+
- [Storage Entries](#storage-entries)
|
|
41
|
+
- [Authentication Requirements](#authentication-requirements)
|
|
42
|
+
- [Token Validation](#token-validation)
|
|
39
43
|
|
|
40
44
|
# Civic Auth Client SDK
|
|
41
45
|
Civic Auth offers a simple, flexible, and fast way to integrate authentication into your applications.
|
|
@@ -550,3 +554,35 @@ Each method is designed to be used in a server-side context and includes proper
|
|
|
550
554
|
### Server-Side Token Validation
|
|
551
555
|
|
|
552
556
|
The CivicAuth interface automatically validates tokens for you when using `getUser()` or `getTokens()` methods, providing an extra layer of security for your server-side authentication logic.
|
|
557
|
+
|
|
558
|
+
## Authentication Storage and State
|
|
559
|
+
|
|
560
|
+
Civic Auth SDK maintains several storage entries to track authentication state. Understanding these entries is helpful for debugging and understanding the authentication flow. These tokens can be stored either in cookies (server-side token exchange) or in local storage (client-side token exchange) depending on your configuration.
|
|
561
|
+
|
|
562
|
+
### Storage Entries
|
|
563
|
+
|
|
564
|
+
| Entry | Purpose | Required for Authentication | Notes |
|
|
565
|
+
|--------|---------|--------------------------|-------|
|
|
566
|
+
| `id_token` | Contains the ID token that verifies the user's identity | **Yes** | Primary token used for authentication |
|
|
567
|
+
| `access_token` | Contains the OAuth2 access token | No | Optional as of version 0.6.0 - used for API access |
|
|
568
|
+
| `refresh_token` | Used to refresh tokens when they expire | No | Stored as a session-only entry with no expiry |
|
|
569
|
+
| `access_token_expires_at` | Tracks when the access token expires | No | Used for client-side token refresh scheduling |
|
|
570
|
+
|
|
571
|
+
### Authentication Requirements
|
|
572
|
+
|
|
573
|
+
For a user to be considered authenticated, the SDK requires:
|
|
574
|
+
|
|
575
|
+
1. A valid `id_token` to be present in storage
|
|
576
|
+
2. The ID token must not be expired
|
|
577
|
+
|
|
578
|
+
### Token Validation
|
|
579
|
+
|
|
580
|
+
The SDK validates tokens using the following checks:
|
|
581
|
+
|
|
582
|
+
- Signature verification against the OAuth provider's public keys
|
|
583
|
+
- Expiration time validation
|
|
584
|
+
- Issuer validation
|
|
585
|
+
- Audience validation
|
|
586
|
+
- Additional optional claim validations based on your application's requirements
|
|
587
|
+
|
|
588
|
+
If token validation fails, the user will be automatically redirected to re-authenticate.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGvC,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,CACpC,sBAAsB,GACtB;IACE,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,YAAY,CAAC;KACrB,CAAC;CACH,CACJ,GAAG;IAGF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,kBAAkB,GAAG;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAKF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,sBAAsB,EAAE,UAAU,CAiEtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,iBAAiB,YACpB,OAAO,CAAC,UAAU,CAAC,KAC1B,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGvC,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,CACpC,sBAAsB,GACtB;IACE,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,YAAY,CAAC;KACrB,CAAC;CACH,CACJ,GAAG;IAGF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,kBAAkB,GAAG;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAKF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,sBAAsB,EAAE,UAAU,CAiEtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,iBAAiB,YACpB,OAAO,CAAC,UAAU,CAAC,KAC1B,sBAiDF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,qBAAqB,eAAgB,UAAU,mBACrC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAyDy7T,CAAC;6BAAsG,CAAC;;;sBAAke,CAAC;yBAA4H,CAAC;;;qBAA+H,CAAC;;;;;;;;;;;;;;;;;;iBAA8pE,CAAC;;;;;;;6BAAg6C,CAAC;sBAAoC,CAAC;;aAAoC,CAAC;;6BAA0D,CAAC;oBAA8B,CAAC;0BAAkE,CAAC;;qBAA2C,CAAC;mBAAiC,CAAC;;wBAA+C,CAAC;eAAmD,CAAC;iBAA4C,CAAC;2BAAyC,CAAC;;;;;;;;;yBAA4zC,CAAC;6BAAwC,CAAC;;;eAAkD,CAAC;mBAAuB,CAAC;;;;CADlwgB,CAAC"}
|
package/dist/nextjs/config.js
CHANGED
|
@@ -115,47 +115,18 @@ export const resolveAuthConfig = (config = {}) => {
|
|
|
115
115
|
: undefined,
|
|
116
116
|
basePath: process.env._civic_auth_base_path || "",
|
|
117
117
|
});
|
|
118
|
-
// Ensure "/api/auth/**" is always excluded
|
|
118
|
+
// Ensure "/api/auth/**" is always excluded
|
|
119
119
|
const finalExclude = new Set([
|
|
120
120
|
...defaultAuthConfig.exclude,
|
|
121
121
|
...(configFromEnv.exclude || []),
|
|
122
122
|
...(config.exclude ?? []),
|
|
123
123
|
]);
|
|
124
|
-
//
|
|
124
|
+
// Perform a deep merge of the configurations
|
|
125
125
|
const mergedConfig = merge.withOptions({ mergeArrays: false }, defaultAuthConfig, configFromEnv, config);
|
|
126
|
-
//
|
|
127
|
-
const effectiveBasePath = mergedConfig.basePath || "";
|
|
128
|
-
// STEP 3: Apply basePath to cookie paths, respecting explicit user overrides
|
|
129
|
-
if (effectiveBasePath && mergedConfig.cookies) {
|
|
130
|
-
// Handle user cookie path
|
|
131
|
-
const userExplicitPath = config.cookies?.user?.path;
|
|
132
|
-
if (mergedConfig.cookies.user) {
|
|
133
|
-
if (userExplicitPath === undefined || userExplicitPath === "/") {
|
|
134
|
-
mergedConfig.cookies.user.path = effectiveBasePath;
|
|
135
|
-
}
|
|
136
|
-
// If userExplicitPath is defined and not '/', it was already set by the merge
|
|
137
|
-
}
|
|
138
|
-
// Handle token cookie paths
|
|
139
|
-
if (mergedConfig.cookies.tokens) {
|
|
140
|
-
Object.keys(mergedConfig.cookies.tokens).forEach((key) => {
|
|
141
|
-
const tokenKey = key;
|
|
142
|
-
const userExplicitTokenPath = config.cookies?.tokens?.[tokenKey]?.path;
|
|
143
|
-
if (userExplicitTokenPath === undefined ||
|
|
144
|
-
userExplicitTokenPath === "/") {
|
|
145
|
-
// Ensure the token itself exists in mergedConfig before assigning path
|
|
146
|
-
if (mergedConfig.cookies?.tokens?.[tokenKey]) {
|
|
147
|
-
mergedConfig.cookies.tokens[tokenKey].path = effectiveBasePath;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
// If userExplicitTokenPath is defined and not '/', it was already set by the merge
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// Apply the ensured exclude list
|
|
126
|
+
// Override the exclude list with the ensured list
|
|
155
127
|
mergedConfig.exclude = Array.from(finalExclude);
|
|
156
128
|
logger.debug("Config from environment:", JSON.stringify(configFromEnv, null, 2));
|
|
157
|
-
logger.debug("
|
|
158
|
-
logger.debug("Resolved config (final):", JSON.stringify(mergedConfig, null, 2));
|
|
129
|
+
logger.debug("Resolved config:", JSON.stringify(mergedConfig, null, 2));
|
|
159
130
|
if (mergedConfig.clientId === undefined) {
|
|
160
131
|
throw new Error("Civic Auth client ID is required");
|
|
161
132
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable turbo/no-undeclared-env-vars */\nimport type { NextConfig } from \"next\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport {\n CodeVerifier,\n type CookieConfig,\n OAuthTokenTypes,\n type TokensCookieConfig,\n} from \"@/shared/lib/types.js\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { merge } from \"ts-deepmerge\";\nimport { sanitizeBasePath } from \"./utils.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nexport type CookiesConfigObject = {\n tokens: TokensCookieConfig;\n user: CookieConfig;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfigWithDefaults = {\n clientId: string;\n oauthServer: string;\n callbackUrl: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl: string;\n logoutUrl: string;\n logoutCallbackUrl: string;\n challengeUrl: string;\n refreshUrl: string;\n include: string[];\n exclude: string[];\n cookies: CookiesConfigObject;\n basePath?: string;\n};\n\n/**\n * All possible config values for Civic Auth\n */\nexport type OptionalAuthConfig = Partial<\n | AuthConfigWithDefaults\n | {\n cookies?: {\n tokens?: Partial<TokensCookieConfig>;\n user?: CookieConfig;\n };\n }\n> & {\n // Ensure TypeScript understands these properties are available\n // This doesn't change the public API, just helps TypeScript internally\n callbackUrl?: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl?: string;\n logoutUrl?: string;\n logoutCallbackUrl?: string;\n challengeUrl?: string;\n refreshUrl?: string;\n include?: string[];\n exclude?: string[];\n basePath?: string;\n oauthServer?: string;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfig = OptionalAuthConfig & {\n clientId: string;\n exclude?: string[];\n};\n\nconst defaultServerSecure = !(process.env.NODE_ENV === \"development\");\nconst defaultCookiesMaxAge = 60 * 60; // 1 hour\n\n/**\n * Default configuration values that will be used if not overridden\n */\nexport const defaultAuthConfig: Omit<AuthConfigWithDefaults, \"clientId\"> = {\n oauthServer: DEFAULT_AUTH_SERVER,\n callbackUrl: \"/api/auth/callback\",\n loginSuccessUrl: undefined, // By default, the user is sent to the redirect_url\n challengeUrl: \"/api/auth/challenge\",\n refreshUrl: \"/api/auth/refresh\",\n logoutUrl: \"/api/auth/logout\",\n logoutCallbackUrl: \"/api/auth/logoutcallback\",\n loginUrl: \"/\",\n include: [\"/**\"],\n exclude: [\"/api/auth/**\"],\n basePath: \"\",\n cookies: {\n tokens: {\n [OAuthTokenTypes.ID_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.ACCESS_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.REFRESH_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT]: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.COOKIE_NAME]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.APP_URL]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n user: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n};\n\n/**\n * Resolves the authentication configuration by combining:\n * 1. Default values\n * 2. Environment variables (set internally by the plugin)\n * 3. Explicitly passed configuration\n *\n * Config will be merged deeply, with arrays not merged, so that the\n * default include list (for example) [\"/*\"] will not be added\n *\n * Note: Developers should not set _civic_auth_* environment variables directly.\n * Instead, pass configuration to the createCivicAuthPlugin in next.config.js:\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * callbackUrl: '/custom/callback',\n * })\n * ```\n */\nexport const resolveAuthConfig = (\n config: Partial<AuthConfig> = {},\n): AuthConfigWithDefaults => {\n // Read configuration that was set by the plugin via environment variables\n const configFromEnv = withoutUndefined({\n clientId: process.env._civic_auth_client_id,\n oauthServer: process.env._civic_oauth_server,\n callbackUrl: process.env._civic_auth_callback_url,\n loginSuccessUrl: process.env._civic_auth_login_success_url,\n challengeUrl: process.env._civic_auth_challenge_url,\n loginUrl: process.env._civic_auth_login_url,\n logoutUrl: process.env._civic_auth_logout_url,\n logoutCallbackUrl: process.env._civic_auth_logout_callback_url,\n refreshUrl: process.env._civic_auth_refresh_url,\n include: process.env._civic_auth_includes?.split(\",\"),\n exclude: process.env._civic_auth_excludes?.split(\",\"),\n cookies: process.env._civic_auth_cookie_config\n ? JSON.parse(process.env._civic_auth_cookie_config)\n : undefined,\n basePath: process.env._civic_auth_base_path || \"\",\n }) as AuthConfig;\n\n // Ensure \"/api/auth/**\" is always excluded, using the default exclude list\n const finalExclude = new Set([\n ...defaultAuthConfig.exclude,\n ...(configFromEnv.exclude || []),\n ...(config.exclude ?? []),\n ]);\n\n // STEP 1: Perform an initial merge to incorporate all sources\n const mergedConfig = merge.withOptions(\n { mergeArrays: false },\n defaultAuthConfig,\n configFromEnv,\n config,\n );\n\n // STEP 2: Determine the effective basePath from the merged configuration\n const effectiveBasePath = mergedConfig.basePath || \"\";\n\n // STEP 3: Apply basePath to cookie paths, respecting explicit user overrides\n if (effectiveBasePath && mergedConfig.cookies) {\n // Handle user cookie path\n const userExplicitPath = config.cookies?.user?.path;\n if (mergedConfig.cookies.user) {\n if (userExplicitPath === undefined || userExplicitPath === \"/\") {\n mergedConfig.cookies.user.path = effectiveBasePath;\n }\n // If userExplicitPath is defined and not '/', it was already set by the merge\n }\n\n // Handle token cookie paths\n if (mergedConfig.cookies.tokens) {\n Object.keys(mergedConfig.cookies.tokens).forEach((key) => {\n const tokenKey = key as keyof TokensCookieConfig;\n const userExplicitTokenPath = config.cookies?.tokens?.[tokenKey]?.path;\n\n if (\n userExplicitTokenPath === undefined ||\n userExplicitTokenPath === \"/\"\n ) {\n // Ensure the token itself exists in mergedConfig before assigning path\n if (mergedConfig.cookies?.tokens?.[tokenKey]) {\n mergedConfig.cookies.tokens[tokenKey]!.path = effectiveBasePath;\n }\n }\n // If userExplicitTokenPath is defined and not '/', it was already set by the merge\n });\n }\n }\n\n // Apply the ensured exclude list\n mergedConfig.exclude = Array.from(finalExclude);\n\n logger.debug(\n \"Config from environment:\",\n JSON.stringify(configFromEnv, null, 2),\n );\n logger.debug(\"User config (input):\", JSON.stringify(config, null, 2));\n logger.debug(\n \"Resolved config (final):\",\n JSON.stringify(mergedConfig, null, 2),\n );\n\n if (mergedConfig.clientId === undefined) {\n throw new Error(\"Civic Auth client ID is required\");\n }\n\n return mergedConfig as AuthConfigWithDefaults & { clientId: string };\n};\n\n/**\n * Creates a Next.js plugin that handles auth configuration.\n *\n * This is the main configuration point for the auth system.\n * Do not set _civic_auth_* environment variables directly - instead,\n * pass your configuration here.\n *\n * The only required field is clientId.\n *\n * Notes:\n * - If you provide explicit URLs, they will be used exactly as provided.\n * - Default URLs will automatically include the basePath from your Next.js config.\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * });\n * ```\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * callbackUrl: '/custom/callback',\n * loginUrl: '/custom/login',\n * logoutUrl: '/custom/logout',\n * logoutCallbackUrl: '/custom/logoutcallback',\n * include: ['/protected/*'],\n * exclude: ['/public/*']\n * })\n * ```\n *\n * The plugin sets internal environment variables that are used by\n * the auth system. These variables should not be set manually.\n */\nexport const createCivicAuthPlugin = (authConfig: AuthConfig) => {\n return (nextConfig?: NextConfig) => {\n logger.debug(\n \"createCivicAuthPlugin nextConfig\",\n JSON.stringify(nextConfig, null, 2),\n );\n\n // Extract basePath from Next.js config\n const basePath = sanitizeBasePath(nextConfig?.basePath || \"\");\n\n // Create a copy of default URLs with basePath added\n const defaultUrlsWithBasePath: Partial<AuthConfig> = {};\n\n // Only apply to URLs that aren't explicitly set in authConfig\n if (basePath) {\n if (!authConfig.callbackUrl)\n defaultUrlsWithBasePath.callbackUrl = `${basePath}/api/auth/callback`;\n if (!authConfig.challengeUrl)\n defaultUrlsWithBasePath.challengeUrl = `${basePath}/api/auth/challenge`;\n if (!authConfig.refreshUrl)\n defaultUrlsWithBasePath.refreshUrl = `${basePath}/api/auth/refresh`;\n if (!authConfig.logoutUrl)\n defaultUrlsWithBasePath.logoutUrl = `${basePath}/api/auth/logout`;\n if (!authConfig.logoutCallbackUrl)\n defaultUrlsWithBasePath.logoutCallbackUrl = `${basePath}/api/auth/logoutcallback`;\n if (!authConfig.loginUrl && authConfig.loginUrl !== \"\")\n defaultUrlsWithBasePath.loginUrl = basePath;\n }\n\n // Create final config with basePath and possibly modified URLs\n const resolvedConfig = resolveAuthConfig({\n ...defaultUrlsWithBasePath,\n ...authConfig,\n basePath,\n });\n\n return {\n ...nextConfig,\n env: {\n ...nextConfig?.env,\n // Internal environment variables - do not set these manually\n _civic_auth_client_id: resolvedConfig.clientId,\n _civic_oauth_server: resolvedConfig.oauthServer,\n _civic_auth_callback_url: resolvedConfig.callbackUrl,\n _civic_auth_login_success_url: resolvedConfig.loginSuccessUrl,\n _civic_auth_challenge_url: resolvedConfig.challengeUrl,\n _civic_auth_login_url: resolvedConfig.loginUrl,\n _civic_auth_logout_url: resolvedConfig.logoutUrl,\n _civic_auth_logout_callback_url: resolvedConfig.logoutCallbackUrl,\n _civic_auth_refresh_url: resolvedConfig.refreshUrl,\n _civic_auth_includes: resolvedConfig.include.join(\",\"),\n _civic_auth_excludes: resolvedConfig.exclude.join(\",\"),\n _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies),\n _civic_auth_base_path: resolvedConfig.basePath,\n },\n };\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,YAAY,EAEZ,eAAe,GAEhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AA+D5C,MAAM,mBAAmB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC;AACtE,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS;AAE/C;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA6C;IACzE,WAAW,EAAE,mBAAmB;IAChC,WAAW,EAAE,oBAAoB;IACjC,eAAe,EAAE,SAAS,EAAE,mDAAmD;IAC/E,YAAY,EAAE,qBAAqB;IACnC,UAAU,EAAE,mBAAmB;IAC/B,SAAS,EAAE,kBAAkB;IAC7B,iBAAiB,EAAE,0BAA0B;IAC7C,QAAQ,EAAE,GAAG;IACb,OAAO,EAAE,CAAC,KAAK,CAAC;IAChB,OAAO,EAAE,CAAC,cAAc,CAAC;IACzB,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE;QACP,MAAM,EAAE;YACN,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE;gBAC1B,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,oBAAoB;aAC7B;YACD,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE;gBAC9B,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,oBAAoB;aAC7B;YACD,CAAC,eAAe,CAAC,aAAa,CAAC,EAAE;gBAC/B,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,oBAAoB;aAC7B;YACD,CAAC,eAAe,CAAC,uBAAuB,CAAC,EAAE;gBACzC,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,KAAK,EAAE,2CAA2C;gBAC5D,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,oBAAoB;aAC7B;YACD,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE;gBAC1B,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,oBAAoB;aAC7B;YACD,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE;gBACtB,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,oBAAoB;aAC7B;SACF;QACD,IAAI,EAAE;YACJ,MAAM,EAAE,mBAAmB;YAC3B,QAAQ,EAAE,KAAK,EAAE,2CAA2C;YAC5D,QAAQ,EAAE,QAAQ;YAClB,IAAI,EAAE,GAAG;YACT,MAAM,EAAE,oBAAoB;SAC7B;KACF;CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,SAA8B,EAAE,EACR,EAAE;IAC1B,0EAA0E;IAC1E,MAAM,aAAa,GAAG,gBAAgB,CAAC;QACrC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;QAC3C,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC5C,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;QACjD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,6BAA6B;QAC1D,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;QACnD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;QAC3C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;QAC7C,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,+BAA+B;QAC9D,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;QAC/C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,CAAC,GAAG,CAAC;QACrD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,CAAC,GAAG,CAAC;QACrD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;YAC5C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;YACnD,CAAC,CAAC,SAAS;QACb,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE;KAClD,CAAe,CAAC;IAEjB,2CAA2C;IAC3C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;QAC3B,GAAG,iBAAiB,CAAC,OAAO;QAC5B,GAAG,CAAC,aAAa,CAAC,OAAO,IAAI,EAAE,CAAC;QAChC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;KAC1B,CAAC,CAAC;IAEH,6CAA6C;IAC7C,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CACpC,EAAE,WAAW,EAAE,KAAK,EAAE,EACtB,iBAAiB,EACjB,aAAa,EACb,MAAM,CACP,CAAC;IAEF,kDAAkD;IAClD,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAEhD,MAAM,CAAC,KAAK,CACV,0BAA0B,EAC1B,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CACvC,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAExE,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,YAA6D,CAAC;AACvE,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,UAAsB,EAAE,EAAE;IAC9D,OAAO,CAAC,UAAuB,EAAE,EAAE;QACjC,MAAM,CAAC,KAAK,CACV,kCAAkC,EAClC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CACpC,CAAC;QAEF,uCAAuC;QACvC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;QAE9D,oDAAoD;QACpD,MAAM,uBAAuB,GAAwB,EAAE,CAAC;QAExD,8DAA8D;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,UAAU,CAAC,WAAW;gBACzB,uBAAuB,CAAC,WAAW,GAAG,GAAG,QAAQ,oBAAoB,CAAC;YACxE,IAAI,CAAC,UAAU,CAAC,YAAY;gBAC1B,uBAAuB,CAAC,YAAY,GAAG,GAAG,QAAQ,qBAAqB,CAAC;YAC1E,IAAI,CAAC,UAAU,CAAC,UAAU;gBACxB,uBAAuB,CAAC,UAAU,GAAG,GAAG,QAAQ,mBAAmB,CAAC;YACtE,IAAI,CAAC,UAAU,CAAC,SAAS;gBACvB,uBAAuB,CAAC,SAAS,GAAG,GAAG,QAAQ,kBAAkB,CAAC;YACpE,IAAI,CAAC,UAAU,CAAC,iBAAiB;gBAC/B,uBAAuB,CAAC,iBAAiB,GAAG,GAAG,QAAQ,0BAA0B,CAAC;YACpF,IAAI,CAAC,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,KAAK,EAAE;gBACpD,uBAAuB,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAChD,CAAC;QAED,+DAA+D;QAC/D,MAAM,cAAc,GAAG,iBAAiB,CAAC;YACvC,GAAG,uBAAuB;YAC1B,GAAG,UAAU;YACb,QAAQ;SACT,CAAC,CAAC;QAEH,OAAO;YACL,GAAG,UAAU;YACb,GAAG,EAAE;gBACH,GAAG,UAAU,EAAE,GAAG;gBAClB,6DAA6D;gBAC7D,qBAAqB,EAAE,cAAc,CAAC,QAAQ;gBAC9C,mBAAmB,EAAE,cAAc,CAAC,WAAW;gBAC/C,wBAAwB,EAAE,cAAc,CAAC,WAAW;gBACpD,6BAA6B,EAAE,cAAc,CAAC,eAAe;gBAC7D,yBAAyB,EAAE,cAAc,CAAC,YAAY;gBACtD,qBAAqB,EAAE,cAAc,CAAC,QAAQ;gBAC9C,sBAAsB,EAAE,cAAc,CAAC,SAAS;gBAChD,+BAA+B,EAAE,cAAc,CAAC,iBAAiB;gBACjE,uBAAuB,EAAE,cAAc,CAAC,UAAU;gBAClD,oBAAoB,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;gBACtD,oBAAoB,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;gBACtD,yBAAyB,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC;gBACjE,qBAAqB,EAAE,cAAc,CAAC,QAAQ;aAC/C;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/* eslint-disable turbo/no-undeclared-env-vars */\nimport type { NextConfig } from \"next\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport {\n CodeVerifier,\n type CookieConfig,\n OAuthTokenTypes,\n type TokensCookieConfig,\n} from \"@/shared/lib/types.js\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { merge } from \"ts-deepmerge\";\nimport { sanitizeBasePath } from \"./utils.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nexport type CookiesConfigObject = {\n tokens: TokensCookieConfig;\n user: CookieConfig;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfigWithDefaults = {\n clientId: string;\n oauthServer: string;\n callbackUrl: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl: string;\n logoutUrl: string;\n logoutCallbackUrl: string;\n challengeUrl: string;\n refreshUrl: string;\n include: string[];\n exclude: string[];\n cookies: CookiesConfigObject;\n basePath?: string;\n};\n\n/**\n * All possible config values for Civic Auth\n */\nexport type OptionalAuthConfig = Partial<\n | AuthConfigWithDefaults\n | {\n cookies?: {\n tokens?: Partial<TokensCookieConfig>;\n user?: CookieConfig;\n };\n }\n> & {\n // Ensure TypeScript understands these properties are available\n // This doesn't change the public API, just helps TypeScript internally\n callbackUrl?: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl?: string;\n logoutUrl?: string;\n logoutCallbackUrl?: string;\n challengeUrl?: string;\n refreshUrl?: string;\n include?: string[];\n exclude?: string[];\n basePath?: string;\n oauthServer?: string;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfig = OptionalAuthConfig & {\n clientId: string;\n exclude?: string[];\n};\n\nconst defaultServerSecure = !(process.env.NODE_ENV === \"development\");\nconst defaultCookiesMaxAge = 60 * 60; // 1 hour\n\n/**\n * Default configuration values that will be used if not overridden\n */\nexport const defaultAuthConfig: Omit<AuthConfigWithDefaults, \"clientId\"> = {\n oauthServer: DEFAULT_AUTH_SERVER,\n callbackUrl: \"/api/auth/callback\",\n loginSuccessUrl: undefined, // By default, the user is sent to the redirect_url\n challengeUrl: \"/api/auth/challenge\",\n refreshUrl: \"/api/auth/refresh\",\n logoutUrl: \"/api/auth/logout\",\n logoutCallbackUrl: \"/api/auth/logoutcallback\",\n loginUrl: \"/\",\n include: [\"/**\"],\n exclude: [\"/api/auth/**\"],\n basePath: \"\",\n cookies: {\n tokens: {\n [OAuthTokenTypes.ID_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.ACCESS_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.REFRESH_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT]: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.COOKIE_NAME]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.APP_URL]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n user: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n};\n\n/**\n * Resolves the authentication configuration by combining:\n * 1. Default values\n * 2. Environment variables (set internally by the plugin)\n * 3. Explicitly passed configuration\n *\n * Config will be merged deeply, with arrays not merged, so that the\n * default include list (for example) [\"/*\"] will not be added\n *\n * Note: Developers should not set _civic_auth_* environment variables directly.\n * Instead, pass configuration to the createCivicAuthPlugin in next.config.js:\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * callbackUrl: '/custom/callback',\n * })\n * ```\n */\nexport const resolveAuthConfig = (\n config: Partial<AuthConfig> = {},\n): AuthConfigWithDefaults => {\n // Read configuration that was set by the plugin via environment variables\n const configFromEnv = withoutUndefined({\n clientId: process.env._civic_auth_client_id,\n oauthServer: process.env._civic_oauth_server,\n callbackUrl: process.env._civic_auth_callback_url,\n loginSuccessUrl: process.env._civic_auth_login_success_url,\n challengeUrl: process.env._civic_auth_challenge_url,\n loginUrl: process.env._civic_auth_login_url,\n logoutUrl: process.env._civic_auth_logout_url,\n logoutCallbackUrl: process.env._civic_auth_logout_callback_url,\n refreshUrl: process.env._civic_auth_refresh_url,\n include: process.env._civic_auth_includes?.split(\",\"),\n exclude: process.env._civic_auth_excludes?.split(\",\"),\n cookies: process.env._civic_auth_cookie_config\n ? JSON.parse(process.env._civic_auth_cookie_config)\n : undefined,\n basePath: process.env._civic_auth_base_path || \"\",\n }) as AuthConfig;\n\n // Ensure \"/api/auth/**\" is always excluded\n const finalExclude = new Set([\n ...defaultAuthConfig.exclude,\n ...(configFromEnv.exclude || []),\n ...(config.exclude ?? []),\n ]);\n\n // Perform a deep merge of the configurations\n const mergedConfig = merge.withOptions(\n { mergeArrays: false },\n defaultAuthConfig,\n configFromEnv,\n config,\n );\n\n // Override the exclude list with the ensured list\n mergedConfig.exclude = Array.from(finalExclude);\n\n logger.debug(\n \"Config from environment:\",\n JSON.stringify(configFromEnv, null, 2),\n );\n logger.debug(\"Resolved config:\", JSON.stringify(mergedConfig, null, 2));\n\n if (mergedConfig.clientId === undefined) {\n throw new Error(\"Civic Auth client ID is required\");\n }\n\n return mergedConfig as AuthConfigWithDefaults & { clientId: string };\n};\n\n/**\n * Creates a Next.js plugin that handles auth configuration.\n *\n * This is the main configuration point for the auth system.\n * Do not set _civic_auth_* environment variables directly - instead,\n * pass your configuration here.\n *\n * The only required field is clientId.\n *\n * Notes:\n * - If you provide explicit URLs, they will be used exactly as provided.\n * - Default URLs will automatically include the basePath from your Next.js config.\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * });\n * ```\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * callbackUrl: '/custom/callback',\n * loginUrl: '/custom/login',\n * logoutUrl: '/custom/logout',\n * logoutCallbackUrl: '/custom/logoutcallback',\n * include: ['/protected/*'],\n * exclude: ['/public/*']\n * })\n * ```\n *\n * The plugin sets internal environment variables that are used by\n * the auth system. These variables should not be set manually.\n */\nexport const createCivicAuthPlugin = (authConfig: AuthConfig) => {\n return (nextConfig?: NextConfig) => {\n logger.debug(\n \"createCivicAuthPlugin nextConfig\",\n JSON.stringify(nextConfig, null, 2),\n );\n\n // Extract basePath from Next.js config\n const basePath = sanitizeBasePath(nextConfig?.basePath || \"\");\n\n // Create a copy of default URLs with basePath added\n const defaultUrlsWithBasePath: Partial<AuthConfig> = {};\n\n // Only apply to URLs that aren't explicitly set in authConfig\n if (basePath) {\n if (!authConfig.callbackUrl)\n defaultUrlsWithBasePath.callbackUrl = `${basePath}/api/auth/callback`;\n if (!authConfig.challengeUrl)\n defaultUrlsWithBasePath.challengeUrl = `${basePath}/api/auth/challenge`;\n if (!authConfig.refreshUrl)\n defaultUrlsWithBasePath.refreshUrl = `${basePath}/api/auth/refresh`;\n if (!authConfig.logoutUrl)\n defaultUrlsWithBasePath.logoutUrl = `${basePath}/api/auth/logout`;\n if (!authConfig.logoutCallbackUrl)\n defaultUrlsWithBasePath.logoutCallbackUrl = `${basePath}/api/auth/logoutcallback`;\n if (!authConfig.loginUrl && authConfig.loginUrl !== \"\")\n defaultUrlsWithBasePath.loginUrl = basePath;\n }\n\n // Create final config with basePath and possibly modified URLs\n const resolvedConfig = resolveAuthConfig({\n ...defaultUrlsWithBasePath,\n ...authConfig,\n basePath,\n });\n\n return {\n ...nextConfig,\n env: {\n ...nextConfig?.env,\n // Internal environment variables - do not set these manually\n _civic_auth_client_id: resolvedConfig.clientId,\n _civic_oauth_server: resolvedConfig.oauthServer,\n _civic_auth_callback_url: resolvedConfig.callbackUrl,\n _civic_auth_login_success_url: resolvedConfig.loginSuccessUrl,\n _civic_auth_challenge_url: resolvedConfig.challengeUrl,\n _civic_auth_login_url: resolvedConfig.loginUrl,\n _civic_auth_logout_url: resolvedConfig.logoutUrl,\n _civic_auth_logout_callback_url: resolvedConfig.logoutCallbackUrl,\n _civic_auth_refresh_url: resolvedConfig.refreshUrl,\n _civic_auth_includes: resolvedConfig.include.join(\",\"),\n _civic_auth_excludes: resolvedConfig.exclude.join(\",\"),\n _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies),\n _civic_auth_base_path: resolvedConfig.basePath,\n },\n };\n };\n};\n"]}
|
package/dist/nextjs/cookies.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import type { KeySetter } from "../shared/lib/types.js";
|
|
2
2
|
import { type CookieConfig } from "../shared/lib/types.js";
|
|
3
|
-
import {
|
|
4
|
-
import { CookieStorage, type CookieStorageSettings } from "../shared/lib/storage.js";
|
|
3
|
+
import { CookieStorage } from "../shared/lib/storage.js";
|
|
5
4
|
/**
|
|
6
5
|
* Clears all authentication cookies on server. Note, this can only be called by the server
|
|
7
6
|
*/
|
|
8
|
-
declare const clearAuthCookies: (
|
|
7
|
+
declare const clearAuthCookies: () => Promise<void>;
|
|
9
8
|
declare class NextjsCookieStorage extends CookieStorage {
|
|
10
|
-
config: Partial<Record<
|
|
11
|
-
|
|
12
|
-
constructor(flatCookieConfig?: Partial<Record<string, CookieConfig>>);
|
|
9
|
+
config: Partial<Record<KeySetter, CookieConfig>>;
|
|
10
|
+
constructor(config?: Partial<Record<KeySetter, CookieConfig>>);
|
|
13
11
|
get(key: string): Promise<string | null>;
|
|
14
12
|
set(key: KeySetter, value: string, cookieConfigOverride?: Partial<CookieConfig>): Promise<void>;
|
|
15
13
|
delete(key: KeySetter): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/nextjs/cookies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/nextjs/cookies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD;;GAEG;AACH,QAAA,MAAM,gBAAgB,qBAGrB,CAAC;AAEF,cAAM,mBAAoB,SAAQ,aAAa;IAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;gBAAhD,MAAM,GAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAAM;IAOlE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKxC,GAAG,CACP,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,oBAAoB,GAAE,OAAO,CAAC,YAAY,CAAM,GAC/C,OAAO,CAAC,IAAI,CAAC;IASV,MAAM,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAI5C;AAED,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC"}
|
package/dist/nextjs/cookies.js
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
import { cookies } from "next/headers.js";
|
|
2
2
|
import {} from "../shared/lib/types.js";
|
|
3
|
-
import {} from "
|
|
4
|
-
import { CookieStorage, } from "../shared/lib/storage.js";
|
|
3
|
+
import { CookieStorage } from "../shared/lib/storage.js";
|
|
5
4
|
import * as session from "../shared/lib/session.js";
|
|
6
5
|
/**
|
|
7
6
|
* Clears all authentication cookies on server. Note, this can only be called by the server
|
|
8
7
|
*/
|
|
9
|
-
const clearAuthCookies = async (
|
|
10
|
-
//
|
|
11
|
-
let flatConfig = {};
|
|
12
|
-
if (resolvedCookies) {
|
|
13
|
-
if (resolvedCookies.tokens) {
|
|
14
|
-
flatConfig = { ...flatConfig, ...resolvedCookies.tokens };
|
|
15
|
-
}
|
|
16
|
-
if (resolvedCookies.user) {
|
|
17
|
-
flatConfig["user"] = resolvedCookies.user;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const cookieStorage = new NextjsCookieStorage(flatConfig);
|
|
8
|
+
const clearAuthCookies = async () => {
|
|
9
|
+
const cookieStorage = new NextjsCookieStorage(); // no cookie storage needed to simply clear it
|
|
21
10
|
await session.clearAuthCookies(cookieStorage);
|
|
22
11
|
};
|
|
23
12
|
class NextjsCookieStorage extends CookieStorage {
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
config;
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
super({
|
|
16
|
+
secure: true,
|
|
17
|
+
httpOnly: true,
|
|
18
|
+
});
|
|
19
|
+
this.config = config;
|
|
26
20
|
}
|
|
27
21
|
async get(key) {
|
|
28
22
|
const cookieStore = await cookies();
|
|
@@ -31,16 +25,14 @@ class NextjsCookieStorage extends CookieStorage {
|
|
|
31
25
|
async set(key, value, cookieConfigOverride = {}) {
|
|
32
26
|
const cookieStore = await cookies();
|
|
33
27
|
const cookieSettings = this.config?.[key] || {
|
|
34
|
-
...
|
|
28
|
+
...this.settings,
|
|
35
29
|
};
|
|
36
30
|
const useCookieSettings = { ...cookieSettings, ...cookieConfigOverride };
|
|
37
31
|
cookieStore.set(key, value, useCookieSettings);
|
|
38
32
|
}
|
|
39
33
|
async delete(key) {
|
|
40
34
|
const cookieStore = await cookies();
|
|
41
|
-
|
|
42
|
-
const path = this.config?.[key]?.path ?? this.settings?.path ?? "/";
|
|
43
|
-
cookieStore.delete({ name: key, path: path }); // Cast to any if delete options are strict
|
|
35
|
+
cookieStore.delete(key);
|
|
44
36
|
}
|
|
45
37
|
}
|
|
46
38
|
export { clearAuthCookies, NextjsCookieStorage };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../src/nextjs/cookies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG1C,OAAO,EAAqB,MAAM,uBAAuB,CAAC;AAC1D,OAAO,
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../src/nextjs/cookies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG1C,OAAO,EAAqB,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,OAAO,MAAM,yBAAyB,CAAC;AACnD;;GAEG;AACH,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;IAClC,MAAM,aAAa,GAAG,IAAI,mBAAmB,EAAE,CAAC,CAAC,8CAA8C;IAC/F,MAAM,OAAO,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,mBAAoB,SAAQ,aAAa;IAC1B;IAAnB,YAAmB,SAAmD,EAAE;QACtE,KAAK,CAAC;YACJ,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAJc,WAAM,GAAN,MAAM,CAA+C;IAKxE,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,OAAO,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAc,EACd,KAAa,EACb,uBAA8C,EAAE;QAEhD,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAgB,CAAC,IAAI;YACxD,GAAG,IAAI,CAAC,QAAQ;SACjB,CAAC;QACF,MAAM,iBAAiB,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,oBAAoB,EAAE,CAAC;QACzE,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAc;QACzB,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;CACF;AAED,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC","sourcesContent":["import { cookies } from \"next/headers.js\";\n\nimport type { KeySetter } from \"@/shared/lib/types.js\";\nimport { type CookieConfig } from \"@/shared/lib/types.js\";\nimport { CookieStorage } from \"@/shared/lib/storage.js\";\nimport * as session from \"@/shared/lib/session.js\";\n/**\n * Clears all authentication cookies on server. Note, this can only be called by the server\n */\nconst clearAuthCookies = async () => {\n const cookieStorage = new NextjsCookieStorage(); // no cookie storage needed to simply clear it\n await session.clearAuthCookies(cookieStorage);\n};\n\nclass NextjsCookieStorage extends CookieStorage {\n constructor(public config: Partial<Record<KeySetter, CookieConfig>> = {}) {\n super({\n secure: true,\n httpOnly: true,\n });\n }\n\n async get(key: string): Promise<string | null> {\n const cookieStore = await cookies();\n return cookieStore.get(key)?.value || null;\n }\n\n async set(\n key: KeySetter,\n value: string,\n cookieConfigOverride: Partial<CookieConfig> = {},\n ): Promise<void> {\n const cookieStore = await cookies();\n const cookieSettings = this.config?.[key as KeySetter] || {\n ...this.settings,\n };\n const useCookieSettings = { ...cookieSettings, ...cookieConfigOverride };\n cookieStore.set(key, value, useCookieSettings);\n }\n\n async delete(key: KeySetter): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(key);\n }\n}\n\nexport { clearAuthCookies, NextjsCookieStorage };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeHandler.d.ts","sourceRoot":"","sources":["../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,oBAAoB,CAAC;AAW7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA6Z9C,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"routeHandler.d.ts","sourceRoot":"","sources":["../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,oBAAoB,CAAC;AAW7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA6Z9C,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAyCvB;AA6CD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,iCAEF,WAAW,KAAG,OAAO,CAAC,YAAY,CAkCjD,CAAC"}
|
|
@@ -162,7 +162,7 @@ const generateHtmlResponseWithCallback = (request, callbackUrl, loginSuccessUrl)
|
|
|
162
162
|
// Get the complete URL including origin and path
|
|
163
163
|
// This ensures we capture any base path like /directory
|
|
164
164
|
const appUrl = window.location.href.substring(
|
|
165
|
-
0,
|
|
165
|
+
0,
|
|
166
166
|
window.location.href.indexOf("/api/auth")
|
|
167
167
|
);
|
|
168
168
|
fetch('${fetchUrl}&appUrl=' + encodeURIComponent(appUrl) + '${loginSuccessSegment}').then((response) => {
|
|
@@ -327,11 +327,18 @@ export async function handleLogout(request, config) {
|
|
|
327
327
|
const state = request.nextUrl.searchParams.get("state");
|
|
328
328
|
if (!state || !idToken) {
|
|
329
329
|
logger.error("handleLogout: missing state or idToken", { state, idToken });
|
|
330
|
+
await clearAuthCookies();
|
|
330
331
|
// if token or state is missing, the logout call to the server will fail,
|
|
331
332
|
// (token has potentially expired already) so go straight to the postLogoutUrl
|
|
332
333
|
// so the user can be signed out.
|
|
333
334
|
return NextResponse.redirect(`${postLogoutUrl}${state ? "?state=" + state : ""}`);
|
|
334
335
|
}
|
|
336
|
+
const displayMode = displayModeFromState(state, "iframe");
|
|
337
|
+
if (displayMode === "iframe") {
|
|
338
|
+
// clear auth cookies immediately before calling the logout endpoint to give faster UX
|
|
339
|
+
await clearAuthCookies();
|
|
340
|
+
await revalidateUrlPath(request.url);
|
|
341
|
+
}
|
|
335
342
|
const logoutUrl = await generateOauthLogoutUrl({
|
|
336
343
|
clientId: resolvedConfigs.clientId,
|
|
337
344
|
idToken,
|
|
@@ -369,8 +376,9 @@ const handleLogoutComplete = async (params) => {
|
|
|
369
376
|
export async function handleLogoutCallback(request, config) {
|
|
370
377
|
const resolvedConfigs = resolveAuthConfig(config);
|
|
371
378
|
const canAccessCookies = !!(await getIdToken(resolvedConfigs));
|
|
379
|
+
// If we have access to cookies, clear them.
|
|
372
380
|
if (canAccessCookies) {
|
|
373
|
-
await clearAuthCookies(
|
|
381
|
+
await clearAuthCookies();
|
|
374
382
|
return handleLogoutComplete({ request, resolvedConfigs });
|
|
375
383
|
}
|
|
376
384
|
// If we don't have access to cookies, render some javascript to the client that will:
|
|
@@ -418,9 +426,7 @@ export const handler = (authConfig = {}) => async (request) => {
|
|
|
418
426
|
const status = error instanceof AuthError ? error.status : 500;
|
|
419
427
|
const message = error instanceof Error ? error.message : "Authentication failed";
|
|
420
428
|
const response = NextResponse.json({ error: message }, { status });
|
|
421
|
-
|
|
422
|
-
const resolvedConfigForError = resolveAuthConfig(authConfig);
|
|
423
|
-
await clearAuthCookies(resolvedConfigForError.cookies); // Pass resolved config's cookies
|
|
429
|
+
await clearAuthCookies();
|
|
424
430
|
return response;
|
|
425
431
|
}
|
|
426
432
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeHandler.js","sourceRoot":"","sources":["../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n LOGOUT_SUCCESS_TEXT,\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport {\n displayModeFromState,\n loginSuccessUrlFromState,\n serverTokenExchangeFromState,\n} from \"@/lib/oauth.js\";\nimport type { AuthConfig, AuthConfigWithDefaults } from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { clearAuthCookies, NextjsCookieStorage } from \"@/nextjs/cookies.js\";\nimport { getUser } from \"@/nextjs/index.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { CodeVerifier, OAuthTokenTypes } from \"@/shared/lib/types.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { clearTokens, generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\nimport { revalidatePath } from \"next/cache.js\";\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport { NextServerAuthenticationRefresherImpl } from \"./NextServerAuthenticationRefresherImpl.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nclass AuthError extends Error {\n constructor(\n message: string,\n public readonly status: number = 401,\n ) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nconst tryUriDecode = (value: string): string | null => {\n try {\n return decodeURIComponent(value);\n } catch (e) {\n logger.error(\"Error decoding URI component:\", e);\n return value;\n }\n};\n\nconst getDecodedQueryParam = (\n request: NextRequest,\n paramName: string,\n): string | null => {\n const queryParam = request.nextUrl.searchParams.get(paramName);\n if (queryParam) {\n return tryUriDecode(queryParam);\n }\n return null;\n};\n\nconst getCookieOrQueryParam = (\n request: NextRequest,\n cookieName: string,\n queryName: string,\n): string | null => {\n // First check the cookie as it might have the full path with base directory\n const cookieValue = request.cookies.get(cookieName)?.value;\n if (cookieValue) {\n return tryUriDecode(cookieValue);\n }\n\n // Fallback to query parameter\n return getDecodedQueryParam(request, queryName);\n};\n\nconst getAppUrl = (request: NextRequest): string | null =>\n getCookieOrQueryParam(request, CodeVerifier.APP_URL, \"appUrl\");\n\n// The loginSuccessUrl can either be decoded from the state parameter, or passed as a cookie or query parameter\nconst getLoginSuccessUrl = (\n request: NextRequest,\n baseUrl?: string | null,\n): string | null => {\n const loginSuccessUrl =\n loginSuccessUrlFromState(request.nextUrl.searchParams.get(\"state\")) ||\n getDecodedQueryParam(request, \"loginSuccessUrl\");\n if (!loginSuccessUrl) {\n return null;\n }\n return baseUrl ? new URL(loginSuccessUrl, baseUrl).href : loginSuccessUrl;\n};\n\nconst getIdToken = async (config: AuthConfig): Promise<string | null> => {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n return cookieStorage.get(OAuthTokenTypes.ID_TOKEN);\n};\n\n/**\n * create a code verifier and challenge for PKCE\n * saving the verifier in a cookie for later use\n * @returns {Promise<NextResponse>}\n */\nasync function handleChallenge(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);\n\n const challenge = await pkceProducer.getCodeChallenge();\n const appUrl = request.nextUrl.searchParams.get(\"appUrl\");\n if (appUrl) {\n await cookieStorage.set(CodeVerifier.APP_URL, appUrl);\n }\n\n return NextResponse.json({ status: \"success\", challenge });\n}\n\nconst getCookieStorageWithUserOverrides = (config: AuthConfig) => {\n const resolvedConfigs = resolveAuthConfig(config);\n return new NextjsCookieStorage({\n ...resolvedConfigs.cookies.tokens,\n user: resolvedConfigs.cookies.user,\n });\n};\nasync function performTokenExchangeAndSetCookies(\n config: AuthConfig,\n code: string,\n state: string,\n appUrl: string,\n) {\n const resolvedConfigs = resolveAuthConfig(config);\n // TODO This is messy, better would be to fix the config.cookies type to always be <name: settings>\n // rather than nesting the tokens-related ones *and* code-verifier inside \"tokens\"\n // (despite code-verifier not relating directly to tokens)\n const cookieStorage = getCookieStorageWithUserOverrides(config);\n\n const callbackUrl = resolveCallbackUrl(resolvedConfigs, appUrl);\n try {\n await resolveOAuthAccessCode(code, state, cookieStorage, {\n ...resolvedConfigs,\n redirectUrl: callbackUrl,\n });\n } catch (error) {\n logger.error(\"Token exchange failed:\", error);\n throw new AuthError(\"Failed to authenticate user\", 401);\n }\n\n const user = await getUser();\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n const userSession = new GenericUserSession(cookieStorage);\n await userSession.set(user);\n}\nasync function handleRefresh(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = getCookieStorageWithUserOverrides(config);\n const userSession = new GenericUserSession(cookieStorage);\n try {\n const onError = (error: Error) => {\n logger.error(\"handleRefresh: Token refresh failed:\", error);\n throw new AuthError(\"Failed to refresh tokens\", 500);\n };\n const refresher = await NextServerAuthenticationRefresherImpl.build(\n {\n clientId: resolvedConfigs.clientId,\n oauthServer: resolvedConfigs.oauthServer,\n redirectUrl: resolvedConfigs.callbackUrl,\n refreshUrl: resolvedConfigs.refreshUrl,\n },\n cookieStorage,\n onError,\n );\n\n const tokens = await refresher.refreshAccessToken();\n const user = await getUser();\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n await userSession.set(user);\n const targetUrl = request.nextUrl.searchParams.get(\"targetUrl\");\n if (targetUrl) {\n return NextResponse.redirect(targetUrl);\n }\n return NextResponse.json({ status: \"success\", tokens });\n } catch (error) {\n logger.error(\n \"handleRefresh: Token refresh failed, clearing tokens:\",\n error,\n );\n await clearTokens(cookieStorage);\n await userSession.clear();\n const targetUrl = request.nextUrl.searchParams.get(\"targetUrl\");\n if (targetUrl) {\n logger.warn(\"redirecting to targetUrl\", targetUrl);\n return NextResponse.redirect(targetUrl);\n }\n return NextResponse.json({ status: \"failed\" });\n }\n}\n\nconst generateHtmlResponseWithCallback = (\n request: NextRequest,\n callbackUrl: string,\n loginSuccessUrl?: string,\n) => {\n // we need to replace the URL with resolved config in case the server is hosted\n // behind a reverse proxy or load balancer\n const requestUrl = new URL(request.url);\n const fetchUrl = `${callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainCallback=true`;\n const loginSuccessSegment = loginSuccessUrl\n ? `&loginSuccessUrl=${encodeURIComponent(loginSuccessUrl)}`\n : \"\";\n const html = `<html lang=\"en\">\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n // Get the complete URL including origin and path\n // This ensures we capture any base path like /directory\n const appUrl = window.location.href.substring(\n 0, \n window.location.href.indexOf(\"/api/auth\")\n );\n fetch('${fetchUrl}&appUrl=' + encodeURIComponent(appUrl) + '${loginSuccessSegment}').then((response) => {\n response.json().then((jsonResponse) => {\n // For login: Redirect back to the callback route, so Case 2 in handleTokenExchangeComplete will be triggered\n // For logout: Redirect to the postLogoutRedirectUrl\n if(jsonResponse.redirectUrl) {\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n</html>\n`;\n const response = new NextResponse(html);\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n};\n\ntype TokkenExchangeCompletInput = {\n request: NextRequest;\n config: AuthConfig;\n loginSuccessUrl?: string | null;\n appUrl?: string | null;\n state: string;\n};\n\nconst handleTokenExchangeComplete = async (\n params: TokkenExchangeCompletInput,\n) => {\n const { request, config, appUrl, loginSuccessUrl, state } = params;\n // Case 1: We are being called via fetch to facilitate access to the cookies. Return success json. The iframe has javascript that will reload this route so Case 2 below will be triggered.\n if (isCalledFromBrowserFetch(request)) {\n logger.debug(\n \"CASE 1: sameDomainCallback=true, returning JSON response with redirect URL\",\n { appUrl, loginSuccessUrl, callbackUrl: config.callbackUrl },\n );\n\n const currentUrl = new URL(request.url);\n // When the client-side JS redirects back here, we don't want to hit this branch again because we can't return JSON from a redirect.\n // So we strip off the sameDomainCallback parameter from the URL.\n const newSearchParams = new URLSearchParams(currentUrl.search);\n newSearchParams.delete(\"sameDomainCallback\");\n\n // We strip off the origin so reverse proxies don't break the redirect.\n const redirectUrl = `${currentUrl.pathname}?${newSearchParams.toString()}${currentUrl.hash}`;\n return NextResponse.json({\n status: \"success\",\n // This makes the iframe redirect back to this route, so Case 2 below will be triggered.\n\n redirectUrl,\n });\n }\n\n // Case 2: We are already authenticated and in iframe mode.\n // Case 2a: We have a custom loginSuccessUrl, so we have to trigger a top-level redirect to it. We do this by rendering a page with the TOKEN_EXCHANGE_SUCCESS_TEXT, which is then picked up by the iframe container.\n // Case 2b: We don't have a custom loginSuccessUrl, so we just redirect to the appUrl. If we don't do this, Cypress tests will fail in the 'no custom loginSuccessUrl' case, because in Cypress an iframe redirect is converted to a top-level redirect,\n // which means the iframe container no longer exists and so can't action the redirect.\n const user = await getUser();\n if (!!user && displayModeFromState(state, \"iframe\") === \"iframe\") {\n if (loginSuccessUrl) {\n logger.debug(\n \"CASE 2a: iframe mode with loginSuccessUrl configured. Returning TOKEN_EXCHANGE_SUCCESS_TEXT to trigger redirect to loginSuccessUrl if any\",\n { loginSuccessUrl },\n );\n const response = new NextResponse(\n `<html lang=\"en\"><span style=\"display:none\">${TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n } else {\n logger.debug(\n \"CASE 2b: iframe mode with no loginSuccessUrl configured. Doing a normal redirect without relying on the iframe container to redirect.\",\n );\n return NextResponse.redirect(`${appUrl}`);\n }\n }\n\n // CASE 3: We're not in iframe mode. We can just do a stright http redirect to the final destination, which is either the loginSuccessUrl if specified, or the appUrl.\n logger.debug(\"CASE 3: non-iframe mode, redirecting to loginSuccessUrl\");\n return NextResponse.redirect(`${loginSuccessUrl || appUrl}`);\n};\n\nasync function handleCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!code || !state) throw new AuthError(\"Bad parameters\", 400);\n\n // appUrl is passed from the client to the server in the query string\n // this is necessary because the server does not have access to the client's window.location.origin\n // and can not accurately determine the appUrl (specially if the app is behind a reverse proxy)\n const appUrl = getAppUrl(request);\n\n // If the integrator has specified a loginSuccessUrl, we'll send the user there after the login completes (including token exchange)\n // We pass in the basePath from config to use as the baseUrl, because we might not have access to the app_url cookie at this point if this was a third-party redirect.\n const loginSuccessUrl = getLoginSuccessUrl(request, appUrl);\n\n const tokenExchangeCompleteParams = {\n request,\n config,\n appUrl,\n state,\n loginSuccessUrl,\n };\n\n const user = await getUser();\n if (user) {\n // User already authenticated.\n return handleTokenExchangeComplete(tokenExchangeCompleteParams);\n }\n\n // User not authenticated yet.\n\n // If we have a code_verifier cookie and the appUrl, we can do a token exchange.\n // Otherwise, just render an empty page.\n // The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.\n // The client will make an additional call to this route with cookies included, at which point we do the token exchange.\n const codeVerifier = request.cookies.get(CodeVerifier.COOKIE_NAME);\n\n if (!codeVerifier || !appUrl) {\n logger.debug(\"handleCallback no code_verifier found\", {\n state,\n serverTokenExchange: serverTokenExchangeFromState(`${state}`),\n });\n let response = new NextResponse(\n `<html lang=\"en\"><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n );\n\n // in server-side token exchange mode we need to launch a page that will trigger the token exchange\n // from the same domain, allowing it access to the code_verifier cookie\n // we only need to do this in redirect mode, as the iframe already triggers a client-side token exchange\n // if no code-verifier cookie is found\n if (state && serverTokenExchangeFromState(state)) {\n logger.debug(\n \"handleCallback serverTokenExchangeFromState, launching redirect page...\",\n {\n requestUrl: request.url,\n configCallbackUrl: resolvedConfigs.callbackUrl,\n },\n );\n // generate a page that will callback to the same domain, allowing access\n // to the code_verifier cookie and passing the appUrl.\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.callbackUrl,\n loginSuccessUrl || undefined,\n );\n }\n logger.debug(\n `handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`,\n );\n return response;\n }\n\n await performTokenExchangeAndSetCookies(resolvedConfigs, code, state, appUrl);\n return handleTokenExchangeComplete(tokenExchangeCompleteParams);\n}\n\n/**\n * If redirectPath is an absolute path, return it as-is.\n * Otherwise for relative paths, append it to the current domain.\n * @param redirectPath\n * @param currentBasePath\n * @returns\n */\nconst getAbsoluteRedirectPath = (\n redirectPath: string,\n currentBasePath: string,\n) => new URL(redirectPath, currentBasePath).href;\n\nconst getPostLogoutRedirectUrl = (\n request: NextRequest,\n config: AuthConfig,\n): string => {\n const { loginUrl } = resolveAuthConfig(config);\n const redirectTarget = loginUrl ?? \"/\";\n\n // if the optional loginUrl is provided and it is an absolute URL,\n // use it as the redirect target\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n if (isAbsoluteRedirect) {\n return redirectTarget;\n }\n\n // if loginUrl is not defined, the appUrl is passed from the client to the server\n // in the query string or cookies. This is necessary because the server does not\n // have access to the client's window.location and can not accurately determine\n // the appUrl (specially if the app is behind a reverse proxy).\n const appUrl = getAppUrl(request);\n if (appUrl) return getAbsoluteRedirectPath(redirectTarget, appUrl);\n\n // If we can't determine the post-logout redirect URL, fallback to the app root as it's the most likely location of the login page.\n return request.nextUrl.origin;\n};\n\nconst revalidateUrlPath = async (url: string) => {\n try {\n const path = new URL(url).pathname;\n revalidatePath(path);\n } catch (error) {\n logger.warn(\"Failed to revalidate path after logout:\", error);\n }\n};\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n\n // Ensure we have the proper app URL including any base path\n const appBaseUrl = getAppUrl(request) || request.url;\n\n // Construct the post-logout URL with the base path included\n const postLogoutUrl = new URL(resolvedConfigs.logoutCallbackUrl, appBaseUrl);\n\n // read the id_token from the cookies\n const idToken = await getIdToken(resolvedConfigs);\n\n // read the state from the query parameters\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!state || !idToken) {\n logger.error(\"handleLogout: missing state or idToken\", { state, idToken });\n // if token or state is missing, the logout call to the server will fail,\n // (token has potentially expired already) so go straight to the postLogoutUrl\n // so the user can be signed out.\n return NextResponse.redirect(\n `${postLogoutUrl}${state ? \"?state=\" + state : \"\"}`,\n );\n }\n\n const logoutUrl = await generateOauthLogoutUrl({\n clientId: resolvedConfigs.clientId,\n idToken,\n state,\n redirectUrl: postLogoutUrl.href,\n oauthServer: resolvedConfigs.oauthServer,\n });\n return NextResponse.redirect(`${logoutUrl.href}`);\n}\n\nconst isCalledFromBrowserFetch = (request: NextRequest) =>\n request.url.includes(\"sameDomainCallback=true\");\n\n/**\n * Called after the cookies have been cleared.\n */\ntype LogoutCompleteInputs = {\n request: NextRequest;\n resolvedConfigs: AuthConfigWithDefaults;\n};\nconst handleLogoutComplete = async (params: LogoutCompleteInputs) => {\n const { request, resolvedConfigs } = params;\n const state = request.nextUrl.searchParams.get(\"state\");\n const postLogoutRedirectUrl = getPostLogoutRedirectUrl(\n request,\n resolvedConfigs,\n );\n\n // If this is a FETCH call, we can only return json. Trying to redirect or return HTML will fail.\n if (isCalledFromBrowserFetch(request)) {\n // The client-side JS will do a window.location.href redirect to postLogoutRedirectUrl when this request returns success.\n return NextResponse.json({\n status: \"success\",\n redirectUrl: postLogoutRedirectUrl,\n });\n }\n\n // If this is a redirect inside an iframe and the user is indeed logged out, render some text that makes the parent redirect to the postLogoutRedirectUrl.\n const user = await getUser();\n if (!user && !!state && displayModeFromState(state, \"iframe\") === \"iframe\") {\n // User is logged out while in an iframe redirect (not a FETCH call).\n // Render some text to make the CivicLogoutIframeContainer redirect to the postLogoutRedirectUrl.\n const response = new NextResponse(\n `<html lang=\"en\"><span style=\"display:none\">${LOGOUT_SUCCESS_TEXT}<a href=\"${[postLogoutRedirectUrl]}\" rel=\"civic-auth-post-logout-redirect-url\"></a></span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n }\n\n revalidateUrlPath(postLogoutRedirectUrl);\n return NextResponse.redirect(postLogoutRedirectUrl);\n};\n\nexport async function handleLogoutCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const canAccessCookies = !!(await getIdToken(resolvedConfigs));\n\n if (canAccessCookies) {\n await clearAuthCookies(resolvedConfigs.cookies);\n return handleLogoutComplete({ request, resolvedConfigs });\n }\n\n // If we don't have access to cookies, render some javascript to the client that will:\n // 1. make a same-domain fetch call back to this endpoint and receive a '{status: \"success\"}' back.\n // 2. On status: success, set the window.location.href to the post-logout redirect URL (usually the appUrl).\n return generateHtmlResponseWithCallback(\n request,\n // The client-side JS will make a fetch call back to this URL.\n resolvedConfigs.logoutCallbackUrl,\n );\n}\n\n/**\n * Creates an authentication handler for Next.js API routes\n *\n * Usage:\n * ```ts\n * // app/api/auth/[...civicauth]/route.ts\n * import { handler } from '@civic/auth/nextjs'\n * export const GET = handler({\n * // optional config overrides\n * })\n * ```\n */\nexport const handler =\n (authConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const config = resolveAuthConfig(authConfig);\n\n try {\n const pathname = request.nextUrl.pathname;\n const pathSegments = pathname.split(\"/\");\n const lastSegment = pathSegments[pathSegments.length - 1];\n\n switch (lastSegment) {\n case \"challenge\":\n return await handleChallenge(request, config);\n case \"callback\":\n return await handleCallback(request, config);\n case \"refresh\":\n return await handleRefresh(request, config);\n case \"logout\":\n return await handleLogout(request, config);\n case \"logoutcallback\":\n return await handleLogoutCallback(request, config);\n default:\n throw new AuthError(`Invalid auth route: ${pathname}`, 404);\n }\n } catch (error) {\n logger.error(\"Auth handler error:\", error);\n\n const status = error instanceof AuthError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : \"Authentication failed\";\n\n const response = NextResponse.json({ error: message }, { status });\n\n // Ensure config is resolved before accessing cookies for clearing\n const resolvedConfigForError = resolveAuthConfig(authConfig);\n await clearAuthCookies(resolvedConfigForError.cookies); // Pass resolved config's cookies\n return response;\n }\n };\n"]}
|
|
1
|
+
{"version":3,"file":"routeHandler.js","sourceRoot":"","sources":["../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n LOGOUT_SUCCESS_TEXT,\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport {\n displayModeFromState,\n loginSuccessUrlFromState,\n serverTokenExchangeFromState,\n} from \"@/lib/oauth.js\";\nimport type { AuthConfig, AuthConfigWithDefaults } from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { clearAuthCookies, NextjsCookieStorage } from \"@/nextjs/cookies.js\";\nimport { getUser } from \"@/nextjs/index.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { CodeVerifier, OAuthTokenTypes } from \"@/shared/lib/types.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { clearTokens, generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\nimport { revalidatePath } from \"next/cache.js\";\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport { NextServerAuthenticationRefresherImpl } from \"./NextServerAuthenticationRefresherImpl.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nclass AuthError extends Error {\n constructor(\n message: string,\n public readonly status: number = 401,\n ) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nconst tryUriDecode = (value: string): string | null => {\n try {\n return decodeURIComponent(value);\n } catch (e) {\n logger.error(\"Error decoding URI component:\", e);\n return value;\n }\n};\n\nconst getDecodedQueryParam = (\n request: NextRequest,\n paramName: string,\n): string | null => {\n const queryParam = request.nextUrl.searchParams.get(paramName);\n if (queryParam) {\n return tryUriDecode(queryParam);\n }\n return null;\n};\n\nconst getCookieOrQueryParam = (\n request: NextRequest,\n cookieName: string,\n queryName: string,\n): string | null => {\n // First check the cookie as it might have the full path with base directory\n const cookieValue = request.cookies.get(cookieName)?.value;\n if (cookieValue) {\n return tryUriDecode(cookieValue);\n }\n\n // Fallback to query parameter\n return getDecodedQueryParam(request, queryName);\n};\n\nconst getAppUrl = (request: NextRequest): string | null =>\n getCookieOrQueryParam(request, CodeVerifier.APP_URL, \"appUrl\");\n\n// The loginSuccessUrl can either be decoded from the state parameter, or passed as a cookie or query parameter\nconst getLoginSuccessUrl = (\n request: NextRequest,\n baseUrl?: string | null,\n): string | null => {\n const loginSuccessUrl =\n loginSuccessUrlFromState(request.nextUrl.searchParams.get(\"state\")) ||\n getDecodedQueryParam(request, \"loginSuccessUrl\");\n if (!loginSuccessUrl) {\n return null;\n }\n return baseUrl ? new URL(loginSuccessUrl, baseUrl).href : loginSuccessUrl;\n};\n\nconst getIdToken = async (config: AuthConfig): Promise<string | null> => {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n return cookieStorage.get(OAuthTokenTypes.ID_TOKEN);\n};\n\n/**\n * create a code verifier and challenge for PKCE\n * saving the verifier in a cookie for later use\n * @returns {Promise<NextResponse>}\n */\nasync function handleChallenge(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);\n\n const challenge = await pkceProducer.getCodeChallenge();\n const appUrl = request.nextUrl.searchParams.get(\"appUrl\");\n if (appUrl) {\n await cookieStorage.set(CodeVerifier.APP_URL, appUrl);\n }\n\n return NextResponse.json({ status: \"success\", challenge });\n}\n\nconst getCookieStorageWithUserOverrides = (config: AuthConfig) => {\n const resolvedConfigs = resolveAuthConfig(config);\n return new NextjsCookieStorage({\n ...resolvedConfigs.cookies.tokens,\n user: resolvedConfigs.cookies.user,\n });\n};\nasync function performTokenExchangeAndSetCookies(\n config: AuthConfig,\n code: string,\n state: string,\n appUrl: string,\n) {\n const resolvedConfigs = resolveAuthConfig(config);\n // TODO This is messy, better would be to fix the config.cookies type to always be <name: settings>\n // rather than nesting the tokens-related ones *and* code-verifier inside \"tokens\"\n // (despite code-verifier not relating directly to tokens)\n const cookieStorage = getCookieStorageWithUserOverrides(config);\n\n const callbackUrl = resolveCallbackUrl(resolvedConfigs, appUrl);\n try {\n await resolveOAuthAccessCode(code, state, cookieStorage, {\n ...resolvedConfigs,\n redirectUrl: callbackUrl,\n });\n } catch (error) {\n logger.error(\"Token exchange failed:\", error);\n throw new AuthError(\"Failed to authenticate user\", 401);\n }\n\n const user = await getUser();\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n const userSession = new GenericUserSession(cookieStorage);\n await userSession.set(user);\n}\nasync function handleRefresh(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = getCookieStorageWithUserOverrides(config);\n const userSession = new GenericUserSession(cookieStorage);\n try {\n const onError = (error: Error) => {\n logger.error(\"handleRefresh: Token refresh failed:\", error);\n throw new AuthError(\"Failed to refresh tokens\", 500);\n };\n const refresher = await NextServerAuthenticationRefresherImpl.build(\n {\n clientId: resolvedConfigs.clientId,\n oauthServer: resolvedConfigs.oauthServer,\n redirectUrl: resolvedConfigs.callbackUrl,\n refreshUrl: resolvedConfigs.refreshUrl,\n },\n cookieStorage,\n onError,\n );\n\n const tokens = await refresher.refreshAccessToken();\n const user = await getUser();\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n await userSession.set(user);\n const targetUrl = request.nextUrl.searchParams.get(\"targetUrl\");\n if (targetUrl) {\n return NextResponse.redirect(targetUrl);\n }\n return NextResponse.json({ status: \"success\", tokens });\n } catch (error) {\n logger.error(\n \"handleRefresh: Token refresh failed, clearing tokens:\",\n error,\n );\n await clearTokens(cookieStorage);\n await userSession.clear();\n const targetUrl = request.nextUrl.searchParams.get(\"targetUrl\");\n if (targetUrl) {\n logger.warn(\"redirecting to targetUrl\", targetUrl);\n return NextResponse.redirect(targetUrl);\n }\n return NextResponse.json({ status: \"failed\" });\n }\n}\n\nconst generateHtmlResponseWithCallback = (\n request: NextRequest,\n callbackUrl: string,\n loginSuccessUrl?: string,\n) => {\n // we need to replace the URL with resolved config in case the server is hosted\n // behind a reverse proxy or load balancer\n const requestUrl = new URL(request.url);\n const fetchUrl = `${callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainCallback=true`;\n const loginSuccessSegment = loginSuccessUrl\n ? `&loginSuccessUrl=${encodeURIComponent(loginSuccessUrl)}`\n : \"\";\n const html = `<html lang=\"en\">\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n // Get the complete URL including origin and path\n // This ensures we capture any base path like /directory\n const appUrl = window.location.href.substring(\n 0,\n window.location.href.indexOf(\"/api/auth\")\n );\n fetch('${fetchUrl}&appUrl=' + encodeURIComponent(appUrl) + '${loginSuccessSegment}').then((response) => {\n response.json().then((jsonResponse) => {\n // For login: Redirect back to the callback route, so Case 2 in handleTokenExchangeComplete will be triggered\n // For logout: Redirect to the postLogoutRedirectUrl\n if(jsonResponse.redirectUrl) {\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n</html>\n`;\n const response = new NextResponse(html);\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n};\n\ntype TokkenExchangeCompletInput = {\n request: NextRequest;\n config: AuthConfig;\n loginSuccessUrl?: string | null;\n appUrl?: string | null;\n state: string;\n};\n\nconst handleTokenExchangeComplete = async (\n params: TokkenExchangeCompletInput,\n) => {\n const { request, config, appUrl, loginSuccessUrl, state } = params;\n // Case 1: We are being called via fetch to facilitate access to the cookies. Return success json. The iframe has javascript that will reload this route so Case 2 below will be triggered.\n if (isCalledFromBrowserFetch(request)) {\n logger.debug(\n \"CASE 1: sameDomainCallback=true, returning JSON response with redirect URL\",\n { appUrl, loginSuccessUrl, callbackUrl: config.callbackUrl },\n );\n\n const currentUrl = new URL(request.url);\n // When the client-side JS redirects back here, we don't want to hit this branch again because we can't return JSON from a redirect.\n // So we strip off the sameDomainCallback parameter from the URL.\n const newSearchParams = new URLSearchParams(currentUrl.search);\n newSearchParams.delete(\"sameDomainCallback\");\n\n // We strip off the origin so reverse proxies don't break the redirect.\n const redirectUrl = `${currentUrl.pathname}?${newSearchParams.toString()}${currentUrl.hash}`;\n return NextResponse.json({\n status: \"success\",\n // This makes the iframe redirect back to this route, so Case 2 below will be triggered.\n\n redirectUrl,\n });\n }\n\n // Case 2: We are already authenticated and in iframe mode.\n // Case 2a: We have a custom loginSuccessUrl, so we have to trigger a top-level redirect to it. We do this by rendering a page with the TOKEN_EXCHANGE_SUCCESS_TEXT, which is then picked up by the iframe container.\n // Case 2b: We don't have a custom loginSuccessUrl, so we just redirect to the appUrl. If we don't do this, Cypress tests will fail in the 'no custom loginSuccessUrl' case, because in Cypress an iframe redirect is converted to a top-level redirect,\n // which means the iframe container no longer exists and so can't action the redirect.\n const user = await getUser();\n if (!!user && displayModeFromState(state, \"iframe\") === \"iframe\") {\n if (loginSuccessUrl) {\n logger.debug(\n \"CASE 2a: iframe mode with loginSuccessUrl configured. Returning TOKEN_EXCHANGE_SUCCESS_TEXT to trigger redirect to loginSuccessUrl if any\",\n { loginSuccessUrl },\n );\n const response = new NextResponse(\n `<html lang=\"en\"><span style=\"display:none\">${TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n } else {\n logger.debug(\n \"CASE 2b: iframe mode with no loginSuccessUrl configured. Doing a normal redirect without relying on the iframe container to redirect.\",\n );\n return NextResponse.redirect(`${appUrl}`);\n }\n }\n\n // CASE 3: We're not in iframe mode. We can just do a stright http redirect to the final destination, which is either the loginSuccessUrl if specified, or the appUrl.\n logger.debug(\"CASE 3: non-iframe mode, redirecting to loginSuccessUrl\");\n return NextResponse.redirect(`${loginSuccessUrl || appUrl}`);\n};\n\nasync function handleCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!code || !state) throw new AuthError(\"Bad parameters\", 400);\n\n // appUrl is passed from the client to the server in the query string\n // this is necessary because the server does not have access to the client's window.location.origin\n // and can not accurately determine the appUrl (specially if the app is behind a reverse proxy)\n const appUrl = getAppUrl(request);\n\n // If the integrator has specified a loginSuccessUrl, we'll send the user there after the login completes (including token exchange)\n // We pass in the basePath from config to use as the baseUrl, because we might not have access to the app_url cookie at this point if this was a third-party redirect.\n const loginSuccessUrl = getLoginSuccessUrl(request, appUrl);\n\n const tokenExchangeCompleteParams = {\n request,\n config,\n appUrl,\n state,\n loginSuccessUrl,\n };\n\n const user = await getUser();\n if (user) {\n // User already authenticated.\n return handleTokenExchangeComplete(tokenExchangeCompleteParams);\n }\n\n // User not authenticated yet.\n\n // If we have a code_verifier cookie and the appUrl, we can do a token exchange.\n // Otherwise, just render an empty page.\n // The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.\n // The client will make an additional call to this route with cookies included, at which point we do the token exchange.\n const codeVerifier = request.cookies.get(CodeVerifier.COOKIE_NAME);\n\n if (!codeVerifier || !appUrl) {\n logger.debug(\"handleCallback no code_verifier found\", {\n state,\n serverTokenExchange: serverTokenExchangeFromState(`${state}`),\n });\n let response = new NextResponse(\n `<html lang=\"en\"><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n );\n\n // in server-side token exchange mode we need to launch a page that will trigger the token exchange\n // from the same domain, allowing it access to the code_verifier cookie\n // we only need to do this in redirect mode, as the iframe already triggers a client-side token exchange\n // if no code-verifier cookie is found\n if (state && serverTokenExchangeFromState(state)) {\n logger.debug(\n \"handleCallback serverTokenExchangeFromState, launching redirect page...\",\n {\n requestUrl: request.url,\n configCallbackUrl: resolvedConfigs.callbackUrl,\n },\n );\n // generate a page that will callback to the same domain, allowing access\n // to the code_verifier cookie and passing the appUrl.\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.callbackUrl,\n loginSuccessUrl || undefined,\n );\n }\n logger.debug(\n `handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`,\n );\n return response;\n }\n\n await performTokenExchangeAndSetCookies(resolvedConfigs, code, state, appUrl);\n return handleTokenExchangeComplete(tokenExchangeCompleteParams);\n}\n\n/**\n * If redirectPath is an absolute path, return it as-is.\n * Otherwise for relative paths, append it to the current domain.\n * @param redirectPath\n * @param currentBasePath\n * @returns\n */\nconst getAbsoluteRedirectPath = (\n redirectPath: string,\n currentBasePath: string,\n) => new URL(redirectPath, currentBasePath).href;\n\nconst getPostLogoutRedirectUrl = (\n request: NextRequest,\n config: AuthConfig,\n): string => {\n const { loginUrl } = resolveAuthConfig(config);\n const redirectTarget = loginUrl ?? \"/\";\n\n // if the optional loginUrl is provided and it is an absolute URL,\n // use it as the redirect target\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n if (isAbsoluteRedirect) {\n return redirectTarget;\n }\n\n // if loginUrl is not defined, the appUrl is passed from the client to the server\n // in the query string or cookies. This is necessary because the server does not\n // have access to the client's window.location and can not accurately determine\n // the appUrl (specially if the app is behind a reverse proxy).\n const appUrl = getAppUrl(request);\n if (appUrl) return getAbsoluteRedirectPath(redirectTarget, appUrl);\n\n // If we can't determine the post-logout redirect URL, fallback to the app root as it's the most likely location of the login page.\n return request.nextUrl.origin;\n};\n\nconst revalidateUrlPath = async (url: string) => {\n try {\n const path = new URL(url).pathname;\n revalidatePath(path);\n } catch (error) {\n logger.warn(\"Failed to revalidate path after logout:\", error);\n }\n};\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n\n // Ensure we have the proper app URL including any base path\n const appBaseUrl = getAppUrl(request) || request.url;\n\n // Construct the post-logout URL with the base path included\n const postLogoutUrl = new URL(resolvedConfigs.logoutCallbackUrl, appBaseUrl);\n\n // read the id_token from the cookies\n const idToken = await getIdToken(resolvedConfigs);\n\n // read the state from the query parameters\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!state || !idToken) {\n logger.error(\"handleLogout: missing state or idToken\", { state, idToken });\n await clearAuthCookies();\n // if token or state is missing, the logout call to the server will fail,\n // (token has potentially expired already) so go straight to the postLogoutUrl\n // so the user can be signed out.\n return NextResponse.redirect(\n `${postLogoutUrl}${state ? \"?state=\" + state : \"\"}`,\n );\n }\n\n const displayMode = displayModeFromState(state, \"iframe\");\n if (displayMode === \"iframe\") {\n // clear auth cookies immediately before calling the logout endpoint to give faster UX\n await clearAuthCookies();\n await revalidateUrlPath(request.url);\n }\n\n const logoutUrl = await generateOauthLogoutUrl({\n clientId: resolvedConfigs.clientId,\n idToken,\n state,\n redirectUrl: postLogoutUrl.href,\n oauthServer: resolvedConfigs.oauthServer,\n });\n return NextResponse.redirect(`${logoutUrl.href}`);\n}\n\nconst isCalledFromBrowserFetch = (request: NextRequest) =>\n request.url.includes(\"sameDomainCallback=true\");\n\n/**\n * Called after the cookies have been cleared.\n */\ntype LogoutCompleteInputs = {\n request: NextRequest;\n resolvedConfigs: AuthConfigWithDefaults;\n};\nconst handleLogoutComplete = async (params: LogoutCompleteInputs) => {\n const { request, resolvedConfigs } = params;\n const state = request.nextUrl.searchParams.get(\"state\");\n const postLogoutRedirectUrl = getPostLogoutRedirectUrl(\n request,\n resolvedConfigs,\n );\n\n // If this is a FETCH call, we can only return json. Trying to redirect or return HTML will fail.\n if (isCalledFromBrowserFetch(request)) {\n // The client-side JS will do a window.location.href redirect to postLogoutRedirectUrl when this request returns success.\n return NextResponse.json({\n status: \"success\",\n redirectUrl: postLogoutRedirectUrl,\n });\n }\n\n // If this is a redirect inside an iframe and the user is indeed logged out, render some text that makes the parent redirect to the postLogoutRedirectUrl.\n const user = await getUser();\n if (!user && !!state && displayModeFromState(state, \"iframe\") === \"iframe\") {\n // User is logged out while in an iframe redirect (not a FETCH call).\n // Render some text to make the CivicLogoutIframeContainer redirect to the postLogoutRedirectUrl.\n const response = new NextResponse(\n `<html lang=\"en\"><span style=\"display:none\">${LOGOUT_SUCCESS_TEXT}<a href=\"${[postLogoutRedirectUrl]}\" rel=\"civic-auth-post-logout-redirect-url\"></a></span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n }\n\n revalidateUrlPath(postLogoutRedirectUrl);\n return NextResponse.redirect(postLogoutRedirectUrl);\n};\n\nexport async function handleLogoutCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const canAccessCookies = !!(await getIdToken(resolvedConfigs));\n\n // If we have access to cookies, clear them.\n if (canAccessCookies) {\n await clearAuthCookies();\n return handleLogoutComplete({ request, resolvedConfigs });\n }\n\n // If we don't have access to cookies, render some javascript to the client that will:\n // 1. make a same-domain fetch call back to this endpoint and receive a '{status: \"success\"}' back.\n // 2. On status: success, set the window.location.href to the post-logout redirect URL (usually the appUrl).\n return generateHtmlResponseWithCallback(\n request,\n // The client-side JS will make a fetch call back to this URL.\n resolvedConfigs.logoutCallbackUrl,\n );\n}\n\n/**\n * Creates an authentication handler for Next.js API routes\n *\n * Usage:\n * ```ts\n * // app/api/auth/[...civicauth]/route.ts\n * import { handler } from '@civic/auth/nextjs'\n * export const GET = handler({\n * // optional config overrides\n * })\n * ```\n */\nexport const handler =\n (authConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const config = resolveAuthConfig(authConfig);\n\n try {\n const pathname = request.nextUrl.pathname;\n const pathSegments = pathname.split(\"/\");\n const lastSegment = pathSegments[pathSegments.length - 1];\n\n switch (lastSegment) {\n case \"challenge\":\n return await handleChallenge(request, config);\n case \"callback\":\n return await handleCallback(request, config);\n case \"refresh\":\n return await handleRefresh(request, config);\n case \"logout\":\n return await handleLogout(request, config);\n case \"logoutcallback\":\n return await handleLogoutCallback(request, config);\n default:\n throw new AuthError(`Invalid auth route: ${pathname}`, 404);\n }\n } catch (error) {\n logger.error(\"Auth handler error:\", error);\n\n const status = error instanceof AuthError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : \"Authentication failed\";\n\n const response = NextResponse.json({ error: message }, { status });\n\n await clearAuthCookies();\n return response;\n }\n };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientTokenExchangeSessionProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAU1D,MAAM,MAAM,wCAAwC,GAAG;IACrD,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D,CAAC;AAcF,QAAA,MAAM,iCAAiC,yDACkC,CAAC;AAE1E,KAAK,qCAAqC,GAAG;IAC3C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,kCAAkC,kBAErC,qCAAqC,
|
|
1
|
+
{"version":3,"file":"ClientTokenExchangeSessionProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAU1D,MAAM,MAAM,wCAAwC,GAAG;IACrD,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D,CAAC;AAcF,QAAA,MAAM,iCAAiC,yDACkC,CAAC;AAE1E,KAAK,qCAAqC,GAAG;IAC3C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,kCAAkC,kBAErC,qCAAqC,qDAyMvC,CAAC;AAEF,YAAY,EAAE,qCAAqC,IAAI,kBAAkB,EAAE,CAAC;AAC5E,OAAO,EACL,kCAAkC,EAClC,iCAAiC,GAClC,CAAC"}
|
|
@@ -32,6 +32,10 @@ const ClientTokenExchangeSessionProvider = ({ children, }) => {
|
|
|
32
32
|
const { startSignIn, authStatus } = useSignIn({
|
|
33
33
|
displayMode: authConfig?.displayMode || "iframe",
|
|
34
34
|
});
|
|
35
|
+
// this state is used to track if the logout was triggered
|
|
36
|
+
// so that we disable auto-start signIn which won't work until the auth-server
|
|
37
|
+
// cookies have been fully cleared
|
|
38
|
+
const [logoutTriggered, setLogoutTriggered] = useState(false);
|
|
35
39
|
// Add a ref to track processed codes
|
|
36
40
|
const processedCodes = useRef(new Set());
|
|
37
41
|
useEffect(() => {
|
|
@@ -89,6 +93,7 @@ const ClientTokenExchangeSessionProvider = ({ children, }) => {
|
|
|
89
93
|
setSession(session);
|
|
90
94
|
}, [authService]);
|
|
91
95
|
const onSignOut = useCallback(() => {
|
|
96
|
+
setLogoutTriggered(true);
|
|
92
97
|
setSession(null);
|
|
93
98
|
}, []);
|
|
94
99
|
useEffect(() => {
|
|
@@ -144,7 +149,9 @@ const ClientTokenExchangeSessionProvider = ({ children, }) => {
|
|
|
144
149
|
// But only if we're not in an iframe (to prevent infinite loops in embedded scenarios)
|
|
145
150
|
if (!isInIframe && authConfig) {
|
|
146
151
|
const ref = getIframeRef(iframeRef?.current, true);
|
|
147
|
-
if
|
|
152
|
+
// if logout was triggered, we don't want to auto-start sign-in
|
|
153
|
+
// as the auth-server cookies will not be cleared yet
|
|
154
|
+
if (ref && authConfig?.displayMode === "iframe" && !logoutTriggered) {
|
|
148
155
|
startSignIn();
|
|
149
156
|
}
|
|
150
157
|
}
|
|
@@ -169,6 +176,7 @@ const ClientTokenExchangeSessionProvider = ({ children, }) => {
|
|
|
169
176
|
isInIframe,
|
|
170
177
|
isLoading,
|
|
171
178
|
startSignIn,
|
|
179
|
+
logoutTriggered,
|
|
172
180
|
]);
|
|
173
181
|
const value = useMemo(() => ({
|
|
174
182
|
data: session,
|