@civic/auth 0.6.1-beta.3 → 0.6.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/README.md +7 -0
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +1 -5
- package/dist/nextjs/config.js.map +1 -1
- package/dist/nextjs/hooks/useUserCookie.d.ts.map +1 -1
- package/dist/nextjs/hooks/useUserCookie.js.map +1 -1
- package/dist/nextjs/middleware.d.ts.map +1 -1
- package/dist/nextjs/middleware.js +51 -18
- package/dist/nextjs/middleware.js.map +1 -1
- package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
- package/dist/nextjs/providers/NextAuthProvider.js +0 -1
- package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
- package/dist/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/nextjs/routeHandler.js +8 -0
- package/dist/nextjs/routeHandler.js.map +1 -1
- package/dist/shared/hooks/useSignIn.d.ts +4 -9
- package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
- package/dist/shared/hooks/useSignIn.js +42 -75
- package/dist/shared/hooks/useSignIn.js.map +1 -1
- package/dist/shared/providers/AuthContext.d.ts +2 -7
- package/dist/shared/providers/AuthContext.d.ts.map +1 -1
- package/dist/shared/providers/AuthContext.js.map +1 -1
- package/dist/shared/providers/UserProvider.d.ts +1 -5
- package/dist/shared/providers/UserProvider.d.ts.map +1 -1
- package/dist/shared/providers/UserProvider.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/vanillajs/auth/AuthenticationEvents.d.ts.map +1 -1
- package/dist/vanillajs/auth/AuthenticationEvents.js +2 -2
- package/dist/vanillajs/auth/AuthenticationEvents.js.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts +107 -68
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +412 -389
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/{handlers/OAuthCallbackHandler.d.ts → OAuthCallbackHandler.d.ts} +2 -2
- package/dist/vanillajs/auth/OAuthCallbackHandler.d.ts.map +1 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.js +143 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.js.map +1 -0
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
- package/dist/vanillajs/auth/SessionManager.js +2 -2
- package/dist/vanillajs/auth/SessionManager.js.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.js +2 -2
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.d.ts +0 -33
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.js +36 -163
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
- package/dist/vanillajs/index.d.ts +2 -2
- package/dist/vanillajs/index.d.ts.map +1 -1
- package/dist/vanillajs/index.js +2 -2
- package/dist/vanillajs/index.js.map +1 -1
- package/dist/vanillajs/services/ApiService.d.ts.map +1 -1
- package/dist/vanillajs/services/ApiService.js +2 -2
- package/dist/vanillajs/services/ApiService.js.map +1 -1
- package/dist/vanillajs/types/index.d.ts +10 -15
- package/dist/vanillajs/types/index.d.ts.map +1 -1
- package/dist/vanillajs/types/index.js +10 -15
- package/dist/vanillajs/types/index.js.map +1 -1
- package/dist/vanillajs/utils/auth-utils.d.ts +1 -2
- package/dist/vanillajs/utils/auth-utils.d.ts.map +1 -1
- package/dist/vanillajs/utils/auth-utils.js +3 -6
- package/dist/vanillajs/utils/auth-utils.js.map +1 -1
- package/dist/vanillajs/utils/logger.d.ts +15 -16
- package/dist/vanillajs/utils/logger.d.ts.map +1 -1
- package/dist/vanillajs/utils/logger.js +19 -35
- package/dist/vanillajs/utils/logger.js.map +1 -1
- package/package.json +1 -6
- package/dist/vanillajs/auth/config/ConfigProcessor.d.ts +0 -6
- package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +0 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.js +0 -59
- package/dist/vanillajs/auth/config/ConfigProcessor.js.map +0 -1
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts +0 -40
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +0 -1
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +0 -388
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +0 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.d.ts +0 -170
- package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +0 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.js +0 -367
- package/dist/vanillajs/auth/handlers/MessageHandler.js.map +0 -1
- package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.d.ts.map +0 -1
- package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.js +0 -301
- package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.js.map +0 -1
- package/dist/vanillajs/auth/handlers/PopupHandler.d.ts +0 -108
- package/dist/vanillajs/auth/handlers/PopupHandler.d.ts.map +0 -1
- package/dist/vanillajs/auth/handlers/PopupHandler.js +0 -333
- package/dist/vanillajs/auth/handlers/PopupHandler.js.map +0 -1
- package/dist/vanillajs/auth/types/AuthTypes.d.ts +0 -128
- package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +0 -1
- package/dist/vanillajs/auth/types/AuthTypes.js +0 -40
- package/dist/vanillajs/auth/types/AuthTypes.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# 0.6.1 fix NextJS middleware authentication rules
|
|
2
|
+
- fix NextJS middleware authentication rules to handle invalid token clearing
|
|
3
|
+
|
|
1
4
|
# 0.6.0 accessToken no longer pre-requisite for authenticated state
|
|
2
5
|
- Only a valid idToken is required in state for the user to be considered authenticated
|
|
3
6
|
- 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
|
package/README.md
CHANGED
|
@@ -352,6 +352,13 @@ export const config = {
|
|
|
352
352
|
}
|
|
353
353
|
```
|
|
354
354
|
|
|
355
|
+
**Token Handling Behavior:**
|
|
356
|
+
- **Valid tokens**: User passes through to protected routes
|
|
357
|
+
- **Refresh token available**: Automatically redirects to refresh endpoint to rehydrate session with `targetUrl` parameter
|
|
358
|
+
- **Expired tokens without refresh**: Redirects to logout callback to clear bad tokens, then to login
|
|
359
|
+
- **No tokens**: Redirects to login URL
|
|
360
|
+
- **Login URL access**: Always allowed regardless of authentication state to prevent redirect loops
|
|
361
|
+
|
|
355
362
|
#### Middleware Chaining
|
|
356
363
|
|
|
357
364
|
If you are already using middleware in your Next.js app, then you can chain them with Civic Auth as follows:
|
|
@@ -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;
|
|
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,sBA2CF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,qBAAqB,eAAgB,UAAU,mBACrC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAyDsmU,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;;;;CAD/6gB,CAAC"}
|
package/dist/nextjs/config.js
CHANGED
|
@@ -7,8 +7,6 @@ import { sanitizeBasePath } from "./utils.js";
|
|
|
7
7
|
const logger = loggers.nextjs.handlers.auth;
|
|
8
8
|
const defaultServerSecure = !(process.env.NODE_ENV === "development");
|
|
9
9
|
const defaultCookiesMaxAge = 60 * 60; // 1 hour
|
|
10
|
-
// In development, allow client-side reading of ID token for easier debugging and testing
|
|
11
|
-
const defaultIdTokenHttpOnly = process.env.NODE_ENV === "development" ? false : true;
|
|
12
10
|
/**
|
|
13
11
|
* Default configuration values that will be used if not overridden
|
|
14
12
|
*/
|
|
@@ -28,7 +26,7 @@ export const defaultAuthConfig = {
|
|
|
28
26
|
tokens: {
|
|
29
27
|
[OAuthTokenTypes.ID_TOKEN]: {
|
|
30
28
|
secure: defaultServerSecure,
|
|
31
|
-
httpOnly:
|
|
29
|
+
httpOnly: true,
|
|
32
30
|
sameSite: "strict",
|
|
33
31
|
path: "/",
|
|
34
32
|
maxAge: defaultCookiesMaxAge,
|
|
@@ -127,8 +125,6 @@ export const resolveAuthConfig = (config = {}) => {
|
|
|
127
125
|
const mergedConfig = merge.withOptions({ mergeArrays: false }, defaultAuthConfig, configFromEnv, config);
|
|
128
126
|
// Override the exclude list with the ensured list
|
|
129
127
|
mergedConfig.exclude = Array.from(finalExclude);
|
|
130
|
-
logger.debug("Config from environment:", JSON.stringify(configFromEnv, null, 2));
|
|
131
|
-
logger.debug("Resolved config:", JSON.stringify(mergedConfig, null, 2));
|
|
132
128
|
if (mergedConfig.clientId === undefined) {
|
|
133
129
|
throw new Error("Civic Auth client ID is required");
|
|
134
130
|
}
|
|
@@ -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// In development, allow client-side reading of ID token for easier debugging and testing\nconst defaultIdTokenHttpOnly =\n process.env.NODE_ENV === \"development\" ? false : true;\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: defaultIdTokenHttpOnly,\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"]}
|
|
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\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 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUserCookie.d.ts","sourceRoot":"","sources":["../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"useUserCookie.d.ts","sourceRoot":"","sources":["../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAwBpD,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,WAAW;;;;kCAuBA,eAAe;;CA+EjE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUserCookie.js","sourceRoot":"","sources":["../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM1C,MAAM,oBAAoB,GAAG,IAAI,oBAAoB,EAAE,CAAC;AACxD,MAAM,yBAAyB,GAAG,GAA2B,EAAE;IAC7D,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAC7C,WAAW,CAAC,IAAI,CACW,CAAC;IAC9B,MAAM,aAAa,GAAG,oBAAoB,CAAC,OAAO,CAChD,eAAe,CAAC,QAAQ,CACG,CAAC;
|
|
1
|
+
{"version":3,"file":"useUserCookie.js","sourceRoot":"","sources":["../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { EmptyObject, User } from \"@/types.js\";\nimport { OAuthTokenTypes, UserStorage } from \"@/shared/lib/types.js\";\nimport { objectsAreEqual } from \"@/lib/obj.js\";\nimport { BrowserCookieStorage } from \"@/shared/index.js\";\nimport { useIsClient } from \"usehooks-ts\";\n\ntype UserAndTokenFromCookie = {\n [UserStorage.USER]: User | undefined;\n [OAuthTokenTypes.ID_TOKEN]: string | undefined;\n};\nconst browserCookieStorage = new BrowserCookieStorage();\nconst getUserAndTokenFromCookie = (): UserAndTokenFromCookie => {\n const userCookie = browserCookieStorage.getSync(\n UserStorage.USER,\n ) as unknown as string | null;\n const idTokenCookie = browserCookieStorage.getSync(\n OAuthTokenTypes.ID_TOKEN,\n ) as unknown as string | null;\n return {\n [UserStorage.USER]: userCookie ? JSON.parse(userCookie) : undefined,\n [OAuthTokenTypes.ID_TOKEN]: idTokenCookie || undefined,\n };\n};\n\nexport const useUserCookie = <T extends EmptyObject>() => {\n // need to make sure this is only run on the client\n // because it uses cookies that expect a document object to be present to read from\n const isClient = useIsClient();\n const response =\n (isClient && getUserAndTokenFromCookie()) || ({} as UserAndTokenFromCookie);\n // initialise user and token from cookies so that we don't\n // have to wait for the first fetch to expose these values\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokenTypes.ID_TOKEN];\n\n // we need both a ref and state for the user and token\n // because the ref is used to compare the previous value\n // to the new value to see if it has changed\n // and the state is used to trigger a re-render\n // when the value changes\n const userRef = useRef(userData);\n const tokenRef = useRef(tokenData);\n const [user, setUser] = useState<User<T> | null>(userData);\n const [idToken, setToken] = useState<string | undefined>(tokenData);\n const [userChanged, setUserChanged] = useState<boolean>(false);\n const [initialFetchComplete, setInitialFetchComplete] = useState(!!userData);\n\n const fetchUser = useCallback((abortController?: AbortController) => {\n if (abortController?.signal.aborted) {\n setInitialFetchComplete(true);\n return;\n }\n\n const response = getUserAndTokenFromCookie() || {};\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokenTypes.ID_TOKEN];\n\n if (abortController?.signal.aborted) {\n setInitialFetchComplete(true);\n return;\n }\n\n // we use objectsAreEqual here comparing the object references could trigger\n // unnecessary re-renders if the object is the same but a new reference is created\n if (!objectsAreEqual(userData, userRef.current)) {\n userRef.current = userData || null;\n setUser(userData || null);\n setUserChanged(true);\n }\n if (tokenData !== tokenRef.current) {\n tokenRef.current = tokenData;\n setToken(tokenData);\n }\n setInitialFetchComplete(true);\n }, []);\n\n /**\n * Set up a listener for when the user cookies change which will be triggered\n * by server-side during token exchange. We are able to receive these updates as the auth\n * calls will be running in the iframe and the cookies will be set in the parent window.\n */\n useEffect(() => {\n let abortController = new AbortController();\n const cookieListener = () => {\n // pass an abort controller to fetchUser to cancel any in-flight requests\n // that might have been triggered before re-render\n abortController = new AbortController();\n fetchUser(abortController);\n };\n\n document.addEventListener(\"visibilitychange\", cookieListener);\n window.addEventListener(\"storage\", cookieListener);\n window.addEventListener(\"focus\", cookieListener);\n\n // set the user and token ref from cookies again as the component has now mounted\n // so cookies might be available that weren't there at initialisation above\n const response =\n getUserAndTokenFromCookie() || ({} as UserAndTokenFromCookie);\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokenTypes.ID_TOKEN];\n userRef.current = userData;\n tokenRef.current = tokenData;\n setUser(userData);\n setToken(tokenData);\n fetchUser(abortController);\n\n // poll for changes to the cookies every 2 seconds\n // this is required as react doesn't have a built-in hook that will change on cookie changes\n const intervalId = setInterval(cookieListener, 2000);\n\n return () => {\n abortController.abort();\n document.removeEventListener(\"visibilitychange\", cookieListener);\n window.removeEventListener(\"storage\", cookieListener);\n window.removeEventListener(\"focus\", cookieListener);\n clearInterval(intervalId);\n };\n }, [fetchUser]);\n\n return {\n user,\n idToken,\n userChanged,\n fetchUser,\n isLoading: !initialFetchComplete,\n };\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,YAAY,CAAC;AA+B3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAuB1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,2BACd,sBAAsB,WACrC,WAAW,KACnB,OAAO,CAAC,WAAW,CAoBrB,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,YAAY,CAAC;AA+B3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAuB1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,2BACd,sBAAsB,WACrC,WAAW,KACnB,OAAO,CAAC,WAAW,CAoBrB,CAAC;AAyHF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,gBACZ,kBAAkB,eACf,WAAW,KAAG,OAAO,CAAC,YAAY,CAOjD,CAAC;AAEJ;;;;;;;GAOG;AAEH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,UAAU,GACrB,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAEjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,UAAU,GAAE,kBAAuB,gBAExC,UAAU,KACrB,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CAQrD"}
|
|
@@ -75,44 +75,77 @@ export const validateAuthTokensIfPresent = async (authConfigWithDefaults, reques
|
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
77
|
// internal - used by all exported functions
|
|
78
|
+
/**
|
|
79
|
+
* Core authentication middleware logic.
|
|
80
|
+
*
|
|
81
|
+
* Flow:
|
|
82
|
+
* 1. Always validate tokens first to determine authentication state
|
|
83
|
+
* 2. Skip protection for Civic Auth system URLs and excluded paths
|
|
84
|
+
* 3. For unauthenticated users on protected routes:
|
|
85
|
+
* - If refresh token exists: redirect to refresh endpoint
|
|
86
|
+
* - If expired tokens exist: redirect to logout callback to clear them
|
|
87
|
+
* - If on login URL: allow access (prevents redirect loops)
|
|
88
|
+
* - Otherwise: redirect to login
|
|
89
|
+
* 4. Allow authenticated users to continue
|
|
90
|
+
*/
|
|
78
91
|
const applyAuth = async (authConfig, request) => {
|
|
79
92
|
const authConfigWithDefaults = resolveAuthConfig(authConfig);
|
|
80
|
-
//
|
|
93
|
+
// Always validate tokens first to determine authentication state
|
|
81
94
|
const session = await validateAuthTokensIfPresent(authConfigWithDefaults, request);
|
|
82
|
-
|
|
95
|
+
logger.debug("applyAuth session data:", session);
|
|
96
|
+
// Skip auth protection for Civic Auth system URLs (callback, challenge, logout)
|
|
83
97
|
if ([
|
|
84
|
-
authConfigWithDefaults.loginUrl,
|
|
85
98
|
authConfigWithDefaults.callbackUrl,
|
|
86
99
|
authConfigWithDefaults.challengeUrl,
|
|
87
100
|
authConfigWithDefaults.logoutCallbackUrl,
|
|
88
101
|
authConfigWithDefaults.logoutUrl,
|
|
89
102
|
].includes(request.nextUrl.pathname) &&
|
|
90
103
|
request.method === "GET") {
|
|
91
|
-
logger.debug("→ Skipping auth check - this
|
|
104
|
+
logger.debug("→ Skipping auth check - this a URL defined in authConfig", request.nextUrl.pathname);
|
|
92
105
|
return undefined;
|
|
93
106
|
}
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
// Skip auth protection for paths not in include patterns (except loginUrl)
|
|
108
|
+
if (request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&
|
|
109
|
+
!matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)) {
|
|
110
|
+
logger.debug("→ Skipping auth check - path not in include patterns", request.nextUrl.pathname);
|
|
96
111
|
return undefined;
|
|
97
112
|
}
|
|
98
|
-
|
|
99
|
-
|
|
113
|
+
// Skip auth protection for paths in exclude patterns (except loginUrl)
|
|
114
|
+
if (request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&
|
|
115
|
+
matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)) {
|
|
116
|
+
logger.debug("→ Skipping auth check - path in exclude patterns", request.nextUrl.pathname);
|
|
100
117
|
return undefined;
|
|
101
118
|
}
|
|
102
|
-
//
|
|
119
|
+
// Handle unauthenticated users on protected routes
|
|
103
120
|
if (!session.authenticated) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
const targetUrl = request.nextUrl.origin + request.nextUrl.pathname;
|
|
122
|
+
// Avoid redirect loops by checking if already in a redirect flow
|
|
123
|
+
if (!request.nextUrl.searchParams.has("targetUrl")) {
|
|
124
|
+
// Attempt session rehydration if refresh token exists
|
|
125
|
+
if (session.refreshToken) {
|
|
126
|
+
const refreshUrl = new URL(authConfigWithDefaults.refreshUrl, request.nextUrl.origin);
|
|
127
|
+
refreshUrl.searchParams.set("targetUrl", targetUrl);
|
|
128
|
+
const redirectUrl = `${refreshUrl.toString()}`;
|
|
129
|
+
logger.debug(`→ Refresh token found - redirecting to "${redirectUrl}"`);
|
|
130
|
+
return NextResponse.redirect(redirectUrl);
|
|
131
|
+
}
|
|
132
|
+
// Clear expired/invalid tokens if they exist without refresh token
|
|
133
|
+
if (session.accessToken || session.idToken) {
|
|
134
|
+
const clearBadTokensUrl = new URL(authConfigWithDefaults.logoutCallbackUrl, request.nextUrl.origin);
|
|
135
|
+
clearBadTokensUrl.searchParams.set("targetUrl", targetUrl);
|
|
136
|
+
logger.debug(`→ Invalid tokens found without refresh - clearing via "${clearBadTokensUrl}"`);
|
|
137
|
+
return NextResponse.redirect(clearBadTokensUrl);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Allow access to login page to prevent redirect loops
|
|
141
|
+
if (request.nextUrl.pathname === authConfigWithDefaults.loginUrl) {
|
|
142
|
+
logger.debug(`→ Allowing access to login page for unauthenticated user`);
|
|
143
|
+
return undefined;
|
|
112
144
|
}
|
|
145
|
+
// Final fallback: redirect to login
|
|
113
146
|
const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.nextUrl.origin);
|
|
114
147
|
const redirectUrl = `${loginUrl.toString()}`;
|
|
115
|
-
logger.debug(`→ No valid
|
|
148
|
+
logger.debug(`→ No valid tokens found - redirecting to login "${redirectUrl}"`);
|
|
116
149
|
return NextResponse.redirect(redirectUrl);
|
|
117
150
|
}
|
|
118
151
|
logger.debug("→ Auth check passed");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * logger.debug('in custom middleware', request.nextUrl.pathname);\n * return NextResponse.next();\n * })\n *\n * Option 3: use if other middleware is needed - specifying auth config\n * const withCivicAuth = auth({ loginUrl: '/login', include: ['/[.*]/user'] })\n * export default withCivicAuth((request) => {\n * logger.debug('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport type {\n AuthConfigWithDefaults,\n OptionalAuthConfig,\n} from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport type { AuthStorage, SessionData } from \"@/types.js\";\n\nconst logger = loggers.nextjs.middleware;\n\n/**\n * CookieStorage implementation for NextJS middleware context that works with NextRequest\n */\nclass NextjsReadOnlyRequestCookieStorage implements AuthStorage {\n constructor(private request: NextRequest) {}\n\n async get(key: string): Promise<string | null> {\n return this.request.cookies.get(key)?.value || null;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async set(key: string, value: string): Promise<void> {\n // In middleware, we can only set cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot set cookies directly in middleware\");\n throw new Error(\"Cannot set cookies directly in middleware\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async delete(key: string): Promise<void> {\n // In middleware, we can only delete cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot delete cookies directly in middleware\");\n throw new Error(\"Cannot delete cookies directly in middleware\");\n }\n}\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n return matchGlob(pathname, pattern);\n });\n\n/**\n * use a ServerAuthenticationResolver to validate the existing session\n * using NextJS cookie storage\n * @param authConfigWithDefaults\n * @param request NextRequest object from middleware\n * @returns {Promise<SessionData>}\n */\nexport const validateAuthTokensIfPresent = async (\n authConfigWithDefaults: AuthConfigWithDefaults,\n request: NextRequest,\n): Promise<SessionData> => {\n try {\n // TODO: evaluate a more performant way to validate tokens\n // than having to call and verify the JWT tokens on every request\n const storage = new NextjsReadOnlyRequestCookieStorage(request);\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n },\n storage,\n );\n // validate the existing session but don't auto-refresh as we can't set cookies in middleware\n const existingSession =\n await authSessionService.validateExistingSession(false);\n return existingSession;\n } catch (error) {\n logger.error(\"Error validating tokens\", error);\n return { authenticated: false };\n }\n};\n// internal - used by all exported functions\nconst applyAuth = async (\n authConfig: OptionalAuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n // Check for any valid auth token\n const session = await validateAuthTokensIfPresent(\n authConfigWithDefaults,\n request,\n );\n\n // skip auth check for any civic auth urls\n if (\n [\n authConfigWithDefaults.loginUrl,\n authConfigWithDefaults.callbackUrl,\n authConfigWithDefaults.challengeUrl,\n authConfigWithDefaults.logoutCallbackUrl,\n authConfigWithDefaults.logoutUrl,\n ].includes(request.nextUrl.pathname) &&\n request.method === \"GET\"\n ) {\n logger.debug(\"→ Skipping auth check - this is the login URL\");\n return undefined;\n }\n\n if (!matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)) {\n logger.debug(\"→ Skipping auth check - path not in include patterns\");\n return undefined;\n }\n\n if (matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)) {\n logger.debug(\"→ Skipping auth check - path in exclude patterns\");\n return undefined;\n }\n\n // Check for either token type\n if (!session.authenticated) {\n if (session.refreshToken) {\n const refreshUrl = new URL(\n authConfigWithDefaults.refreshUrl,\n request.nextUrl.origin,\n );\n // set targetUrl to the original request URL without search params\n // to avoid redirect loops\n refreshUrl.searchParams.set(\n \"targetUrl\",\n request.nextUrl.origin + request.nextUrl.pathname,\n );\n const redirectUrl = `${refreshUrl.toString()}`;\n logger.debug(`→ Refresh token found - redirecting to \"${redirectUrl}\"`);\n return NextResponse.redirect(redirectUrl);\n }\n const loginUrl = new URL(\n authConfigWithDefaults.loginUrl,\n request.nextUrl.origin,\n );\n const redirectUrl = `${loginUrl.toString()}`;\n logger.debug(`→ No valid token found - redirecting to \"${redirectUrl}\"`);\n return NextResponse.redirect(redirectUrl);\n }\n\n logger.debug(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig: OptionalAuthConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n // NextJS doesn't do middleware chaining yet, so this does not mean\n // \"call the next middleware\" - it means \"continue to the route handler\"\n return NextResponse.next();\n };\n\n/**\n * Usage:\n *\n * export default withAuth(async (request) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return auth()(middleware);\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * export default auth(authConfig: AuthConfig ) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: OptionalAuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n return middleware(request);\n };\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,SAAS,MAAM,WAAW,CAAC;AAKlC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AAGxF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;AAEzC;;GAEG;AACH,MAAM,kCAAkC;IAClB;IAApB,YAAoB,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;IAAG,CAAC;IAE5C,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;IACtD,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa;QAClC,8DAA8D;QAC9D,mDAAmD;QACnD,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,iEAAiE;QACjE,mDAAmD;QACnD,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;CACF;AAMD,iBAAiB;AACjB,YAAY;AACZ,QAAQ;AACR,UAAU;AACV,gBAAgB;AAChB,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAE,WAAmB,EAAE,EAAE;IAC1D,MAAM,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACvC,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,iBAAiB;AACjB,YAAY;AACZ,QAAQ;AACR,UAAU;AACV,gBAAgB;AAChB,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,QAAkB,EAAE,EAAE,CAC5D,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEL;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,sBAA8C,EAC9C,OAAoB,EACE,EAAE;IACxB,IAAI,CAAC;QACH,0DAA0D;QAC1D,iEAAiE;QACjE,MAAM,OAAO,GAAG,IAAI,kCAAkC,CAAC,OAAO,CAAC,CAAC;QAChE,MAAM,kBAAkB,GAAG,MAAM,4BAA4B,CAAC,KAAK,CACjE;YACE,GAAG,sBAAsB;YACzB,WAAW,EAAE,sBAAsB,CAAC,WAAW;SAChD,EACD,OAAO,CACR,CAAC;QACF,6FAA6F;QAC7F,MAAM,eAAe,GACnB,MAAM,kBAAkB,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAC1D,OAAO,eAAe,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAC/C,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;AACH,CAAC,CAAC;AACF,4CAA4C;AAC5C;;;;;;;;;;;;GAYG;AACH,MAAM,SAAS,GAAG,KAAK,EACrB,UAA8B,EAC9B,OAAoB,EACe,EAAE;IACrC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC7D,iEAAiE;IACjE,MAAM,OAAO,GAAG,MAAM,2BAA2B,CAC/C,sBAAsB,EACtB,OAAO,CACR,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,OAAO,CAAC,CAAC;IAEjD,gFAAgF;IAChF,IACE;QACE,sBAAsB,CAAC,WAAW;QAClC,sBAAsB,CAAC,YAAY;QACnC,sBAAsB,CAAC,iBAAiB;QACxC,sBAAsB,CAAC,SAAS;KACjC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QACpC,OAAO,CAAC,MAAM,KAAK,KAAK,EACxB,CAAC;QACD,MAAM,CAAC,KAAK,CACV,0DAA0D,EAC1D,OAAO,CAAC,OAAO,CAAC,QAAQ,CACzB,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,2EAA2E;IAC3E,IACE,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,QAAQ;QAC5D,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,sBAAsB,CAAC,OAAO,CAAC,EACvE,CAAC;QACD,MAAM,CAAC,KAAK,CACV,sDAAsD,EACtD,OAAO,CAAC,OAAO,CAAC,QAAQ,CACzB,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,uEAAuE;IACvE,IACE,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,QAAQ;QAC5D,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,sBAAsB,CAAC,OAAO,CAAC,EACtE,CAAC;QACD,MAAM,CAAC,KAAK,CACV,kDAAkD,EAClD,OAAO,CAAC,OAAO,CAAC,QAAQ,CACzB,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,mDAAmD;IACnD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QAEpE,iEAAiE;QACjE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACnD,sDAAsD;YACtD,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,sBAAsB,CAAC,UAAU,EACjC,OAAO,CAAC,OAAO,CAAC,MAAM,CACvB,CAAC;gBACF,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBACpD,MAAM,WAAW,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC/C,MAAM,CAAC,KAAK,CAAC,2CAA2C,WAAW,GAAG,CAAC,CAAC;gBACxE,OAAO,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC5C,CAAC;YAED,mEAAmE;YACnE,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC3C,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAC/B,sBAAsB,CAAC,iBAAiB,EACxC,OAAO,CAAC,OAAO,CAAC,MAAM,CACvB,CAAC;gBACF,iBAAiB,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBAC3D,MAAM,CAAC,KAAK,CACV,0DAA0D,iBAAiB,GAAG,CAC/E,CAAC;gBACF,OAAO,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,QAAQ,EAAE,CAAC;YACjE,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;YACzE,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,oCAAoC;QACpC,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,sBAAsB,CAAC,QAAQ,EAC/B,OAAO,CAAC,OAAO,CAAC,MAAM,CACvB,CAAC;QACF,MAAM,WAAW,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,KAAK,CACV,mDAAmD,WAAW,GAAG,CAClE,CAAC;QACF,OAAO,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GACzB,CAAC,aAAiC,EAAE,EAAE,EAAE,CACxC,KAAK,EAAE,OAAoB,EAAyB,EAAE;IACpD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACtD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,mEAAmE;IACnE,wEAAwE;IACxE,OAAO,YAAY,CAAC,IAAI,EAAE,CAAC;AAC7B,CAAC,CAAC;AAEJ;;;;;;;GAOG;AACH,sDAAsD;AACtD,MAAM,UAAU,QAAQ,CACtB,UAAsB;IAEtB,OAAO,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,IAAI,CAAC,aAAiC,EAAE;IACtD,OAAO,CACL,UAAsB,EAC6B,EAAE;QACrD,OAAO,KAAK,EAAE,OAAoB,EAAyB,EAAE;YAC3D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACtD,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YAE9B,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * logger.debug('in custom middleware', request.nextUrl.pathname);\n * return NextResponse.next();\n * })\n *\n * Option 3: use if other middleware is needed - specifying auth config\n * const withCivicAuth = auth({ loginUrl: '/login', include: ['/[.*]/user'] })\n * export default withCivicAuth((request) => {\n * logger.debug('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport type {\n AuthConfigWithDefaults,\n OptionalAuthConfig,\n} from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport type { AuthStorage, SessionData } from \"@/types.js\";\n\nconst logger = loggers.nextjs.middleware;\n\n/**\n * CookieStorage implementation for NextJS middleware context that works with NextRequest\n */\nclass NextjsReadOnlyRequestCookieStorage implements AuthStorage {\n constructor(private request: NextRequest) {}\n\n async get(key: string): Promise<string | null> {\n return this.request.cookies.get(key)?.value || null;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async set(key: string, value: string): Promise<void> {\n // In middleware, we can only set cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot set cookies directly in middleware\");\n throw new Error(\"Cannot set cookies directly in middleware\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async delete(key: string): Promise<void> {\n // In middleware, we can only delete cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot delete cookies directly in middleware\");\n throw new Error(\"Cannot delete cookies directly in middleware\");\n }\n}\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n return matchGlob(pathname, pattern);\n });\n\n/**\n * use a ServerAuthenticationResolver to validate the existing session\n * using NextJS cookie storage\n * @param authConfigWithDefaults\n * @param request NextRequest object from middleware\n * @returns {Promise<SessionData>}\n */\nexport const validateAuthTokensIfPresent = async (\n authConfigWithDefaults: AuthConfigWithDefaults,\n request: NextRequest,\n): Promise<SessionData> => {\n try {\n // TODO: evaluate a more performant way to validate tokens\n // than having to call and verify the JWT tokens on every request\n const storage = new NextjsReadOnlyRequestCookieStorage(request);\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n },\n storage,\n );\n // validate the existing session but don't auto-refresh as we can't set cookies in middleware\n const existingSession =\n await authSessionService.validateExistingSession(false);\n return existingSession;\n } catch (error) {\n logger.error(\"Error validating tokens\", error);\n return { authenticated: false };\n }\n};\n// internal - used by all exported functions\n/**\n * Core authentication middleware logic.\n *\n * Flow:\n * 1. Always validate tokens first to determine authentication state\n * 2. Skip protection for Civic Auth system URLs and excluded paths\n * 3. For unauthenticated users on protected routes:\n * - If refresh token exists: redirect to refresh endpoint\n * - If expired tokens exist: redirect to logout callback to clear them\n * - If on login URL: allow access (prevents redirect loops)\n * - Otherwise: redirect to login\n * 4. Allow authenticated users to continue\n */\nconst applyAuth = async (\n authConfig: OptionalAuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n // Always validate tokens first to determine authentication state\n const session = await validateAuthTokensIfPresent(\n authConfigWithDefaults,\n request,\n );\n logger.debug(\"applyAuth session data:\", session);\n\n // Skip auth protection for Civic Auth system URLs (callback, challenge, logout)\n if (\n [\n authConfigWithDefaults.callbackUrl,\n authConfigWithDefaults.challengeUrl,\n authConfigWithDefaults.logoutCallbackUrl,\n authConfigWithDefaults.logoutUrl,\n ].includes(request.nextUrl.pathname) &&\n request.method === \"GET\"\n ) {\n logger.debug(\n \"→ Skipping auth check - this a URL defined in authConfig\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Skip auth protection for paths not in include patterns (except loginUrl)\n if (\n request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&\n !matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)\n ) {\n logger.debug(\n \"→ Skipping auth check - path not in include patterns\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Skip auth protection for paths in exclude patterns (except loginUrl)\n if (\n request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&\n matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)\n ) {\n logger.debug(\n \"→ Skipping auth check - path in exclude patterns\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Handle unauthenticated users on protected routes\n if (!session.authenticated) {\n const targetUrl = request.nextUrl.origin + request.nextUrl.pathname;\n\n // Avoid redirect loops by checking if already in a redirect flow\n if (!request.nextUrl.searchParams.has(\"targetUrl\")) {\n // Attempt session rehydration if refresh token exists\n if (session.refreshToken) {\n const refreshUrl = new URL(\n authConfigWithDefaults.refreshUrl,\n request.nextUrl.origin,\n );\n refreshUrl.searchParams.set(\"targetUrl\", targetUrl);\n const redirectUrl = `${refreshUrl.toString()}`;\n logger.debug(`→ Refresh token found - redirecting to \"${redirectUrl}\"`);\n return NextResponse.redirect(redirectUrl);\n }\n\n // Clear expired/invalid tokens if they exist without refresh token\n if (session.accessToken || session.idToken) {\n const clearBadTokensUrl = new URL(\n authConfigWithDefaults.logoutCallbackUrl,\n request.nextUrl.origin,\n );\n clearBadTokensUrl.searchParams.set(\"targetUrl\", targetUrl);\n logger.debug(\n `→ Invalid tokens found without refresh - clearing via \"${clearBadTokensUrl}\"`,\n );\n return NextResponse.redirect(clearBadTokensUrl);\n }\n }\n\n // Allow access to login page to prevent redirect loops\n if (request.nextUrl.pathname === authConfigWithDefaults.loginUrl) {\n logger.debug(`→ Allowing access to login page for unauthenticated user`);\n return undefined;\n }\n\n // Final fallback: redirect to login\n const loginUrl = new URL(\n authConfigWithDefaults.loginUrl,\n request.nextUrl.origin,\n );\n const redirectUrl = `${loginUrl.toString()}`;\n logger.debug(\n `→ No valid tokens found - redirecting to login \"${redirectUrl}\"`,\n );\n return NextResponse.redirect(redirectUrl);\n }\n logger.debug(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig: OptionalAuthConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n // NextJS doesn't do middleware chaining yet, so this does not mean\n // \"call the next middleware\" - it means \"continue to the route handler\"\n return NextResponse.next();\n };\n\n/**\n * Usage:\n *\n * export default withAuth(async (request) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return auth()(middleware);\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * export default auth(authConfig: AuthConfig ) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: OptionalAuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n return middleware(request);\n };\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAe5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAkBrE,KAAK,kCAAkC,GAAG,IAAI,CAC5C,iBAAiB,EACjB,UAAU,CACX,GAAG;IACF,cAAc,EAAE,sBAAsB,CAAC;CACxC,CAAC;AACF,KAAK,0BAA0B,GAAG,IAAI,CACpC,kCAAkC,EAClC,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAC9C,CAAC;
|
|
1
|
+
{"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAe5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAkBrE,KAAK,kCAAkC,GAAG,IAAI,CAC5C,iBAAiB,EACjB,UAAU,CACX,GAAG;IACF,cAAc,EAAE,sBAAsB,CAAC;CACxC,CAAC;AACF,KAAK,0BAA0B,GAAG,IAAI,CACpC,kCAAkC,EAClC,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAC9C,CAAC;AAuJF,QAAA,MAAM,qBAAqB,2BAGxB,0BAA0B,qDA8C5B,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NextAuthProvider.js","sourceRoot":"","sources":["../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n/**\n * A very small context provider for the user object - it takes the user object from the cookie and provides it to the app.\n */\nimport React, {\n startTransition,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n resolveAuthConfig,\n type AuthConfigWithDefaults,\n} from \"@/nextjs/config.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE.js\";\nimport { UserProvider } from \"@/shared/providers/UserProvider.js\";\nimport { useUserCookie } from \"@/nextjs/hooks/useUserCookie.js\";\nimport { CivicAuthConfigProvider } from \"@/shared/providers/CivicAuthConfigContext.js\";\nimport { SessionProvider } from \"@/shared/providers/SessionProvider.js\";\nimport { IframeProvider } from \"@/shared/providers/IframeProvider.js\";\nimport { TokenProvider } from \"@/shared/providers/TokenProvider.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport { BlockDisplay } from \"@/shared/components/BlockDisplay.js\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\nimport { AuthStatus, type UnknownObject, type User } from \"@/types.js\";\nimport { useRefresh } from \"@/nextjs/hooks/useRefresh.js\";\nimport { useCurrentUrl, useSession } from \"@/shared/hooks/index.js\";\nimport { BrowserCookieStorage } from \"@/shared/index.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\nimport { AuthStatusProvider } from \"@/shared/providers/AuthStatusContext.js\";\nimport { useIsClient } from \"usehooks-ts\";\nimport { useRouter } from \"next/navigation.js\";\n\ntype CivicNextAuthTokenProviderInternalProps<TUser extends UnknownObject> =\n NextCivicAuthProviderInternalProps & {\n isLoading: boolean;\n idToken?: string;\n user: User<TUser> | null;\n fetchUser: () => void;\n };\ntype NextCivicAuthProviderInternalProps = Omit<\n AuthProviderProps,\n \"clientId\"\n> & {\n resolvedConfig: AuthConfigWithDefaults;\n};\ntype NextCivicAuthProviderProps = Omit<\n NextCivicAuthProviderInternalProps,\n \"clientId\" | \"resolvedConfig\" | \"redirectUrl\"\n>;\n\nconst CivicNextAuthTokenProviderInternal = <\n TUser extends UnknownObject = UnknownObject,\n>({\n children,\n displayMode = \"iframe\",\n user,\n fetchUser,\n ...props\n}: CivicNextAuthTokenProviderInternalProps<TUser>) => {\n const { iframeMode, resolvedConfig } = props;\n const { iframeRef, setIframeIsVisible, isIframeMounted, setIframeMounted } =\n useIframe();\n const civicAuthConfig = useCivicAuthConfig();\n const { challengeUrl } = resolvedConfig;\n const pkceConsumer = new ConfidentialClientPKCEConsumer(\n challengeUrl,\n resolvedConfig.basePath,\n );\n const { data: session } = useSession();\n const currentUrl = useCurrentUrl();\n\n useEffect(() => {\n if (session?.authenticated) {\n setIframeMounted(false);\n // the session is authenticated, so don't show the login iframe\n setIframeIsVisible(false);\n return;\n }\n }, [session?.authenticated, setIframeIsVisible, setIframeMounted]);\n\n const postSignOut = useCallback(async () => {\n // user is signed out, manually update the user from cookies to not wait for polling\n fetchUser();\n await props?.onSignOut?.();\n }, [fetchUser, props]);\n\n const { signIn, startSignIn, signOut, authStatus } = useSignIn({\n postSignOut,\n pkceConsumer,\n displayMode,\n storage: new BrowserCookieStorage(),\n });\n\n const { error: refreshError } = useRefresh();\n\n useEffect(() => {\n const ref = getIframeRef(iframeRef?.current, true);\n if (\n isIframeMounted &&\n civicAuthConfig &&\n !session?.authenticated &&\n ref &&\n authStatus === AuthStatus.UNAUTHENTICATED &&\n displayMode === \"iframe\" &&\n !currentUrl?.includes(\"code=\")\n ) {\n startSignIn();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n isIframeMounted,\n currentUrl,\n iframeMode,\n iframeRef,\n civicAuthConfig,\n session?.authenticated,\n authStatus,\n startSignIn,\n displayMode,\n ]);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signing out...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n // if the SDK loads in an iframe, we show the loading spinner as the iframe\n // will be waiting to be minimized\n const isInIframe = useIsInIframe();\n // we need this as server-side rendering will not have a window object\n // and will throw an error if we try to access it\n const isClient = useIsClient();\n return !isClient ? null : (\n <TokenProvider>\n <UserProvider\n storage={new BrowserCookieStorage()}\n user={user}\n signOut={signOut}\n signIn={signIn}\n displayMode={displayMode}\n authStatus={authStatus}\n >\n <IFrameAndLoading error={null} isLoading={isInIframe} />\n {isInIframe && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n {children}\n </UserProvider>\n </TokenProvider>\n );\n};\n\nconst CivicNextAuthProviderInternal = ({\n children,\n ...props\n}: NextCivicAuthProviderInternalProps) => {\n const { user, idToken, fetchUser, isLoading, userChanged } = useUserCookie();\n const hasRunRef = useRef(false);\n const router = useRouter();\n\n // if there are any changes in the user object, we need to refresh the page\n // to handle both login and logout cases. We use a 'hasRun' ref to prevent\n // the refresh from running multiple times in a row\n useEffect(() => {\n if (userChanged) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n startTransition(() => {\n router.refresh();\n });\n }\n } else {\n hasRunRef.current = false;\n }\n }, [userChanged, router]);\n\n const session = {\n authenticated: !!user,\n idToken,\n };\n\n return (\n <SessionProvider data={session} isLoading={isLoading}>\n <CivicNextAuthTokenProviderInternal\n {...props}\n user={user}\n idToken={idToken}\n fetchUser={fetchUser}\n isLoading={isLoading}\n >\n {children}\n </CivicNextAuthTokenProviderInternal>\n </SessionProvider>\n );\n};\n\nconst CivicNextAuthProvider = ({\n children,\n ...props\n}: NextCivicAuthProviderProps) => {\n const resolvedConfig = resolveAuthConfig();\n const {\n clientId,\n oauthServer,\n callbackUrl,\n loginSuccessUrl,\n challengeUrl,\n logoutUrl,\n refreshUrl,\n logoutCallbackUrl,\n } = resolvedConfig;\n const [redirectUrl, setRedirectUrl] = useState<string>(\"\");\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const appUrl = globalThis.window.location.origin;\n setRedirectUrl(resolveCallbackUrl(resolvedConfig, appUrl));\n }\n }, [callbackUrl, resolvedConfig]);\n\n return (\n <CivicAuthConfigProvider\n oauthServer={oauthServer}\n clientId={clientId}\n loginSuccessUrl={loginSuccessUrl}\n redirectUrl={redirectUrl}\n logoutRedirectUrl={logoutCallbackUrl}\n nonce={props?.nonce}\n challengeUrl={challengeUrl}\n refreshUrl={refreshUrl}\n logoutUrl={logoutUrl}\n logoutCallbackUrl={logoutCallbackUrl}\n >\n <AuthStatusProvider>\n <IframeProvider iframeMode={props.iframeMode}>\n <CivicNextAuthProviderInternal\n {...props}\n resolvedConfig={resolvedConfig}\n >\n {children}\n </CivicNextAuthProviderInternal>\n </IframeProvider>\n </AuthStatusProvider>\n </CivicAuthConfigProvider>\n );\n};\n\nexport { CivicNextAuthProvider, type NextCivicAuthProviderProps };\n"]}
|
|
1
|
+
{"version":3,"file":"NextAuthProvider.js","sourceRoot":"","sources":["../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb;;GAEG;AACH,OAAO,KAAK,EAAE,EACZ,eAAe,EACf,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAC;AACf,OAAO,EACL,iBAAiB,GAElB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAiC,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAoB/C,MAAM,kCAAkC,GAAG,CAEzC,EACA,QAAQ,EACR,WAAW,GAAG,QAAQ,EACtB,IAAI,EACJ,SAAS,EACT,GAAG,KAAK,EACuC,EAAE,EAAE;IACnD,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IAC7C,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,gBAAgB,EAAE,GACxE,SAAS,EAAE,CAAC;IACd,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAC7C,MAAM,EAAE,YAAY,EAAE,GAAG,cAAc,CAAC;IACxC,MAAM,YAAY,GAAG,IAAI,8BAA8B,CACrD,YAAY,EACZ,cAAc,CAAC,QAAQ,CACxB,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,CAAC;IACvC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;YAC3B,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACxB,+DAA+D;YAC/D,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAEnE,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACzC,oFAAoF;QACpF,SAAS,EAAE,CAAC;QACZ,MAAM,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC;IAC7B,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IAEvB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;QAC7D,WAAW;QACX,YAAY;QACZ,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,UAAU,EAAE,CAAC;IAE7C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACnD,IACE,eAAe;YACf,eAAe;YACf,CAAC,OAAO,EAAE,aAAa;YACvB,GAAG;YACH,UAAU,KAAK,UAAU,CAAC,eAAe;YACzC,WAAW,KAAK,QAAQ;YACxB,CAAC,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,EAC9B,CAAC;YACD,WAAW,EAAE,CAAC;QAChB,CAAC;QACD,uDAAuD;IACzD,CAAC,EAAE;QACD,eAAe;QACf,UAAU;QACV,UAAU;QACV,SAAS;QACT,eAAe;QACf,OAAO,EAAE,aAAa;QACtB,UAAU;QACV,WAAW;QACX,WAAW;KACZ,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,YAAY,CAAC,CAAC;YACtE,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAE5B,2EAA2E;IAC3E,kCAAkC;IAClC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,sEAAsE;IACtE,iDAAiD;IACjD,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,KAAC,aAAa,cACZ,MAAC,YAAY,IACX,OAAO,EAAE,IAAI,oBAAoB,EAAE,EACnC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,UAAU,aAEtB,KAAC,gBAAgB,IAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,GAAI,EACvD,UAAU,IAAI,CACb,KAAC,YAAY,cACX,KAAC,WAAW,KAAG,GACF,CAChB,EACA,QAAQ,IACI,GACD,CACjB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,6BAA6B,GAAG,CAAC,EACrC,QAAQ,EACR,GAAG,KAAK,EAC2B,EAAE,EAAE;IACvC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,aAAa,EAAE,CAAC;IAC7E,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,2EAA2E;IAC3E,0EAA0E;IAC1E,mDAAmD;IACnD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBACvB,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;gBACzB,eAAe,CAAC,GAAG,EAAE;oBACnB,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAE1B,MAAM,OAAO,GAAG;QACd,aAAa,EAAE,CAAC,CAAC,IAAI;QACrB,OAAO;KACR,CAAC;IAEF,OAAO,CACL,KAAC,eAAe,IAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,YAClD,KAAC,kCAAkC,OAC7B,KAAK,EACT,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,YAEnB,QAAQ,GAC0B,GACrB,CACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,EAC7B,QAAQ,EACR,GAAG,KAAK,EACmB,EAAE,EAAE;IAC/B,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;IAC3C,MAAM,EACJ,QAAQ,EACR,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,SAAS,EACT,UAAU,EACV,iBAAiB,GAClB,GAAG,cAAc,CAAC;IACnB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAS,EAAE,CAAC,CAAC;IAE3D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACjD,cAAc,CAAC,kBAAkB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IAElC,OAAO,CACL,KAAC,uBAAuB,IACtB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,eAAe,EAChC,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,KAAK,EAAE,KAAK,EAAE,KAAK,EACnB,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,iBAAiB,EAAE,iBAAiB,YAEpC,KAAC,kBAAkB,cACjB,KAAC,cAAc,IAAC,UAAU,EAAE,KAAK,CAAC,UAAU,YAC1C,KAAC,6BAA6B,OACxB,KAAK,EACT,cAAc,EAAE,cAAc,YAE7B,QAAQ,GACqB,GACjB,GACE,GACG,CAC3B,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAmC,CAAC","sourcesContent":["\"use client\";\n/**\n * A very small context provider for the user object - it takes the user object from the cookie and provides it to the app.\n */\nimport React, {\n startTransition,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n resolveAuthConfig,\n type AuthConfigWithDefaults,\n} from \"@/nextjs/config.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE.js\";\nimport { UserProvider } from \"@/shared/providers/UserProvider.js\";\nimport { useUserCookie } from \"@/nextjs/hooks/useUserCookie.js\";\nimport { CivicAuthConfigProvider } from \"@/shared/providers/CivicAuthConfigContext.js\";\nimport { SessionProvider } from \"@/shared/providers/SessionProvider.js\";\nimport { IframeProvider } from \"@/shared/providers/IframeProvider.js\";\nimport { TokenProvider } from \"@/shared/providers/TokenProvider.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport { BlockDisplay } from \"@/shared/components/BlockDisplay.js\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\nimport { AuthStatus, type UnknownObject, type User } from \"@/types.js\";\nimport { useRefresh } from \"@/nextjs/hooks/useRefresh.js\";\nimport { useCurrentUrl, useSession } from \"@/shared/hooks/index.js\";\nimport { BrowserCookieStorage } from \"@/shared/index.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\nimport { AuthStatusProvider } from \"@/shared/providers/AuthStatusContext.js\";\nimport { useIsClient } from \"usehooks-ts\";\nimport { useRouter } from \"next/navigation.js\";\n\ntype CivicNextAuthTokenProviderInternalProps<TUser extends UnknownObject> =\n NextCivicAuthProviderInternalProps & {\n isLoading: boolean;\n idToken?: string;\n user: User<TUser> | null;\n fetchUser: () => void;\n };\ntype NextCivicAuthProviderInternalProps = Omit<\n AuthProviderProps,\n \"clientId\"\n> & {\n resolvedConfig: AuthConfigWithDefaults;\n};\ntype NextCivicAuthProviderProps = Omit<\n NextCivicAuthProviderInternalProps,\n \"clientId\" | \"resolvedConfig\" | \"redirectUrl\"\n>;\n\nconst CivicNextAuthTokenProviderInternal = <\n TUser extends UnknownObject = UnknownObject,\n>({\n children,\n displayMode = \"iframe\",\n user,\n fetchUser,\n ...props\n}: CivicNextAuthTokenProviderInternalProps<TUser>) => {\n const { iframeMode, resolvedConfig } = props;\n const { iframeRef, setIframeIsVisible, isIframeMounted, setIframeMounted } =\n useIframe();\n const civicAuthConfig = useCivicAuthConfig();\n const { challengeUrl } = resolvedConfig;\n const pkceConsumer = new ConfidentialClientPKCEConsumer(\n challengeUrl,\n resolvedConfig.basePath,\n );\n const { data: session } = useSession();\n const currentUrl = useCurrentUrl();\n\n useEffect(() => {\n if (session?.authenticated) {\n setIframeMounted(false);\n // the session is authenticated, so don't show the login iframe\n setIframeIsVisible(false);\n return;\n }\n }, [session?.authenticated, setIframeIsVisible, setIframeMounted]);\n\n const postSignOut = useCallback(async () => {\n // user is signed out, manually update the user from cookies to not wait for polling\n fetchUser();\n await props?.onSignOut?.();\n }, [fetchUser, props]);\n\n const { signIn, startSignIn, signOut, authStatus } = useSignIn({\n postSignOut,\n pkceConsumer,\n displayMode,\n });\n\n const { error: refreshError } = useRefresh();\n\n useEffect(() => {\n const ref = getIframeRef(iframeRef?.current, true);\n if (\n isIframeMounted &&\n civicAuthConfig &&\n !session?.authenticated &&\n ref &&\n authStatus === AuthStatus.UNAUTHENTICATED &&\n displayMode === \"iframe\" &&\n !currentUrl?.includes(\"code=\")\n ) {\n startSignIn();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n isIframeMounted,\n currentUrl,\n iframeMode,\n iframeRef,\n civicAuthConfig,\n session?.authenticated,\n authStatus,\n startSignIn,\n displayMode,\n ]);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signing out...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n // if the SDK loads in an iframe, we show the loading spinner as the iframe\n // will be waiting to be minimized\n const isInIframe = useIsInIframe();\n // we need this as server-side rendering will not have a window object\n // and will throw an error if we try to access it\n const isClient = useIsClient();\n return !isClient ? null : (\n <TokenProvider>\n <UserProvider\n storage={new BrowserCookieStorage()}\n user={user}\n signOut={signOut}\n signIn={signIn}\n displayMode={displayMode}\n authStatus={authStatus}\n >\n <IFrameAndLoading error={null} isLoading={isInIframe} />\n {isInIframe && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n {children}\n </UserProvider>\n </TokenProvider>\n );\n};\n\nconst CivicNextAuthProviderInternal = ({\n children,\n ...props\n}: NextCivicAuthProviderInternalProps) => {\n const { user, idToken, fetchUser, isLoading, userChanged } = useUserCookie();\n const hasRunRef = useRef(false);\n const router = useRouter();\n\n // if there are any changes in the user object, we need to refresh the page\n // to handle both login and logout cases. We use a 'hasRun' ref to prevent\n // the refresh from running multiple times in a row\n useEffect(() => {\n if (userChanged) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n startTransition(() => {\n router.refresh();\n });\n }\n } else {\n hasRunRef.current = false;\n }\n }, [userChanged, router]);\n\n const session = {\n authenticated: !!user,\n idToken,\n };\n\n return (\n <SessionProvider data={session} isLoading={isLoading}>\n <CivicNextAuthTokenProviderInternal\n {...props}\n user={user}\n idToken={idToken}\n fetchUser={fetchUser}\n isLoading={isLoading}\n >\n {children}\n </CivicNextAuthTokenProviderInternal>\n </SessionProvider>\n );\n};\n\nconst CivicNextAuthProvider = ({\n children,\n ...props\n}: NextCivicAuthProviderProps) => {\n const resolvedConfig = resolveAuthConfig();\n const {\n clientId,\n oauthServer,\n callbackUrl,\n loginSuccessUrl,\n challengeUrl,\n logoutUrl,\n refreshUrl,\n logoutCallbackUrl,\n } = resolvedConfig;\n const [redirectUrl, setRedirectUrl] = useState<string>(\"\");\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const appUrl = globalThis.window.location.origin;\n setRedirectUrl(resolveCallbackUrl(resolvedConfig, appUrl));\n }\n }, [callbackUrl, resolvedConfig]);\n\n return (\n <CivicAuthConfigProvider\n oauthServer={oauthServer}\n clientId={clientId}\n loginSuccessUrl={loginSuccessUrl}\n redirectUrl={redirectUrl}\n logoutRedirectUrl={logoutCallbackUrl}\n nonce={props?.nonce}\n challengeUrl={challengeUrl}\n refreshUrl={refreshUrl}\n logoutUrl={logoutUrl}\n logoutCallbackUrl={logoutCallbackUrl}\n >\n <AuthStatusProvider>\n <IframeProvider iframeMode={props.iframeMode}>\n <CivicNextAuthProviderInternal\n {...props}\n resolvedConfig={resolvedConfig}\n >\n {children}\n </CivicNextAuthProviderInternal>\n </IframeProvider>\n </AuthStatusProvider>\n </CivicAuthConfigProvider>\n );\n};\n\nexport { CivicNextAuthProvider, type NextCivicAuthProviderProps };\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;
|
|
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;AAqa9C,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"}
|
|
@@ -289,6 +289,14 @@ async function handleCallback(request, config) {
|
|
|
289
289
|
const getAbsoluteRedirectPath = (redirectPath, currentBasePath) => new URL(redirectPath, currentBasePath).href;
|
|
290
290
|
const getPostLogoutRedirectUrl = (request, config) => {
|
|
291
291
|
const { loginUrl } = resolveAuthConfig(config);
|
|
292
|
+
// if we have a target URL in the request, it's come from civic middleware
|
|
293
|
+
// and we should use it as the redirect target.
|
|
294
|
+
const targetUrl = request.nextUrl.searchParams.get("targetUrl");
|
|
295
|
+
if (targetUrl) {
|
|
296
|
+
// If a targetUrl is provided, use it as the redirect target.
|
|
297
|
+
// This is useful for redirecting to a specific page after logout.
|
|
298
|
+
return targetUrl;
|
|
299
|
+
}
|
|
292
300
|
const redirectTarget = loginUrl ?? "/";
|
|
293
301
|
// if the optional loginUrl is provided and it is an absolute URL,
|
|
294
302
|
// use it as the redirect target
|