@civic/auth 0.13.1 → 0.13.2

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 CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.13.2 - Fix deep-linking for excluded paths
2
+ - Fix bug where analytics proxy paths (e.g., `/ga/*`, `/gtm/*`, `/ingest/*`) were being captured as return URLs during authentication
3
+ - Excluded paths now skip deep linking entirely, preventing analytics requests from overwriting the intended return URL
4
+ - Updated documentation to recommend adding analytics proxy paths to the `exclude` configuration
5
+
1
6
  # 0.13.1 - Generalised server support for deep-linking
2
7
  - support deep-linking in all servers by setting a return_to cookie and propagating it via state through the OAuth flow
3
8
  - add `deepLinkHandling` configuration option for all server SDKs with three modes: `"fullUrl"`, `"queryParamsOnly"`, `"disabled"`
package/README.md CHANGED
@@ -361,6 +361,8 @@ export const config = {
361
361
  }
362
362
  ```
363
363
 
364
+ > **Note:** If you have analytics proxy rewrites in your `next.config.js` (e.g., for Google Analytics, PostHog, or other tracking services), you should add those paths to the `exclude` configuration option. See [Advanced Configuration](#advanced-configuration) for details.
365
+
364
366
  **Token Handling Behavior:**
365
367
  - **Valid tokens**: User passes through to protected routes
366
368
  - **Refresh token available**: Automatically redirects to refresh endpoint to rehydrate session with `targetUrl` parameter
@@ -454,7 +456,7 @@ export default withCivicAuth(nextConfig) // your next config here
454
456
 
455
457
  Here are the available configuration options:
456
458
 
457
- <table><thead><tr><th width="133">Field</th><th width="100">Required</th><th width="171">Default</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>clientId</td><td>Yes</td><td>-</td><td><code>2cc5633d-2c92-48da-86aa-449634f274b9</code></td><td>The key obtained on signup to <a href="https://auth.civic.com">auth.civic.com</a></td></tr><tr><td>callbackUrl</td><td>No</td><td>/api/auth/callback</td><td>/api/myroute/callback</td><td>The path to route the browser to after a succesful login. Set this value if you are hosting your civic auth API route somewhere other than the default recommended <a href="next.js.md#create-an-api-route">above</a>.</td></tr><tr><td>loginUrl</td><td>No</td><td>/</td><td>/admin</td><td>The path your user will be sent to if they access a resource that needs them to be logged in. If you have a dedicated login page, you can set it here.</td></tr><tr><td>logoutUrl</td><td>No</td><td>/</td><td>/goodbye</td><td>The path your user will be sent to after a successful log-out.</td></tr><tr><td>baseUrl</td><td>No</td><td>-</td><td>https://myapp.com</td><td>The public-facing base URL for apps deployed behind reverse proxies (e.g., Cloudfront + Vercel). When your app is behind a reverse proxy, the middleware may construct redirect URLs using internal origins instead of your public domain. Set this to ensure authentication redirects use the correct public URL.</td></tr><tr><td>autoRedirect</td><td>No</td><td>true</td><td>autoRedirect: false</td><td>When enabled, automatically uses the 'redirect' mode for authentication in browsers that don't support iframe-based authentication (e.g., Safari with passkeys). Instead of users performing authentication in an iframe, the current page will load the login page and they user will be redirected back upon succesfull login completion.</td></tr><tr><td>deepLinkConfig</td><td>No</td><td>"fullUrl"</td><td>"queryParamsOnly"</td><td>Controls how deep links are preserved during authentication. See <a href="#deep-linking">Deep Linking</a> below.</td></tr><tr><td>include</td><td>No</td><td>['/*']</td><td><p>[</p><p> '/admin/*', '/api/admin/*'</p><p>]</p></td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that require a user to be logged-in to access. If not set, will include all paths matched by your Next.js <a href="next.js.md#middleware">middleware</a>.</td></tr><tr><td>exclude</td><td>No</td><td>-</td><td>['public/home']</td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that are excluded from the Civic Auth <a href="next.js.md#middleware">middleware</a>. In some cases, it might be easier and safer to specify exceptions rather than keep an inclusion list up to date.</td></tr></tbody></table>
459
+ <table><thead><tr><th width="133">Field</th><th width="100">Required</th><th width="171">Default</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>clientId</td><td>Yes</td><td>-</td><td><code>2cc5633d-2c92-48da-86aa-449634f274b9</code></td><td>The key obtained on signup to <a href="https://auth.civic.com">auth.civic.com</a></td></tr><tr><td>callbackUrl</td><td>No</td><td>/api/auth/callback</td><td>/api/myroute/callback</td><td>The path to route the browser to after a succesful login. Set this value if you are hosting your civic auth API route somewhere other than the default recommended <a href="next.js.md#create-an-api-route">above</a>.</td></tr><tr><td>loginUrl</td><td>No</td><td>/</td><td>/admin</td><td>The path your user will be sent to if they access a resource that needs them to be logged in. If you have a dedicated login page, you can set it here.</td></tr><tr><td>logoutUrl</td><td>No</td><td>/</td><td>/goodbye</td><td>The path your user will be sent to after a successful log-out.</td></tr><tr><td>baseUrl</td><td>No</td><td>-</td><td>https://myapp.com</td><td>The public-facing base URL for apps deployed behind reverse proxies (e.g., Cloudfront + Vercel). When your app is behind a reverse proxy, the middleware may construct redirect URLs using internal origins instead of your public domain. Set this to ensure authentication redirects use the correct public URL.</td></tr><tr><td>autoRedirect</td><td>No</td><td>true</td><td>autoRedirect: false</td><td>When enabled, automatically uses the 'redirect' mode for authentication in browsers that don't support iframe-based authentication (e.g., Safari with passkeys). Instead of users performing authentication in an iframe, the current page will load the login page and they user will be redirected back upon succesfull login completion.</td></tr><tr><td>deepLinkConfig</td><td>No</td><td>"fullUrl"</td><td>"queryParamsOnly"</td><td>Controls how deep links are preserved during authentication. See <a href="#deep-linking">Deep Linking</a> below.</td></tr><tr><td>include</td><td>No</td><td>['/*']</td><td><p>[</p><p> '/admin/*', '/api/admin/*'</p><p>]</p></td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that require a user to be logged-in to access. If not set, will include all paths matched by your Next.js <a href="next.js.md#middleware">middleware</a>.</td></tr><tr><td>exclude</td><td>No</td><td>-</td><td>['/ga/**/*', '/gtm/**/*', '/ingest/**/*']</td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that are excluded from the Civic Auth <a href="next.js.md#middleware">middleware</a>. <b>Important:</b> If you have analytics proxy rewrites (e.g., for Google Analytics, GTM, or PostHog), add those paths here to prevent them from being captured as return URLs during authentication.</td></tr></tbody></table>
458
460
 
459
461
  ### Deep Linking
460
462
 
@@ -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;AAC9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAW9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAM3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACtC,wBAAwB,sBAAsB,EAC9C,SAAS,6BAA6B,KACrC,OAAO,CAAC,WAAW,CAgBrB,CAAC;AAuHF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACxB,aAAY,kBAAuB,MAC7B,SAAS,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;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,UAAU,GAAE,kBAAuB,IAEpD,YAAY,UAAU,KACrB,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CA2BrD"}
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;AAC9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAW9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAM3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACtC,wBAAwB,sBAAsB,EAC9C,SAAS,6BAA6B,KACrC,OAAO,CAAC,WAAW,CAgBrB,CAAC;AA0HF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACxB,aAAY,kBAAuB,MAC7B,SAAS,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;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,UAAU,GAAE,kBAAuB,IAEpD,YAAY,UAAU,KACrB,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CA2BrD"}
@@ -74,6 +74,13 @@ const applyAuth = async (authConfig, request) => {
74
74
  shouldSkipAuthForSystemUrls: shouldSkipAuthForSystemUrlsCheck,
75
75
  shouldSkipAuthForRoutePatterns: shouldSkipAuthForRoutePatternsCheck,
76
76
  });
77
+ // Skip authentication for routes not matching include/exclude patterns
78
+ // This must happen BEFORE deep linking to prevent capturing excluded paths
79
+ // (e.g., analytics proxy paths like /ga/*, /gtm/*, /ingest/*) as return URLs
80
+ // BUT we still allow the login URL through, as it needs deep linking support
81
+ if (shouldSkipAuthForRoutePatternsCheck && !pathNameIsLoginUrl) {
82
+ return response;
83
+ }
77
84
  // Step 2: Handle deep link cookie for unauthenticated users using CivicAuth
78
85
  // handleDeepLinking automatically detects if we're at loginUrl or a protected route
79
86
  // and applies the appropriate logic for each case
@@ -91,10 +98,6 @@ const applyAuth = async (authConfig, request) => {
91
98
  handleLoginUrl(request.nextUrl.pathname, session, authConfigWithDefaults);
92
99
  return response; // Always allow access to login URL
93
100
  }
94
- // Skip authentication for routes not matching include/exclude patterns
95
- if (shouldSkipAuthForRoutePatternsCheck) {
96
- return response;
97
- }
98
101
  // Handle unauthenticated users on protected routes
99
102
  if (!session.authenticated) {
100
103
  return handleUnauthenticatedUser(session, request, response, storage, authConfigWithDefaults);
@@ -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 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 { SessionData } from \"@/types.js\";\nimport {\n shouldAttemptRefresh,\n shouldSkipAuthForSystemUrls,\n handleLoginUrl,\n shouldSkipAuthForRoutePatterns,\n handleUnauthenticatedUser,\n copyCivicCookies,\n getOriginUrl,\n removeBasePathFromPath,\n} from \"./utils.js\";\nimport { NextjsMiddlewareCookieStorage } from \"./utils.js\";\nimport { UserStorage } from \"@/shared/lib/types.js\";\nimport { CivicAuth } from \"@/server/session.js\";\n\nconst logger = loggers.nextjs.middleware;\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\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 storage: NextjsMiddlewareCookieStorage,\n): Promise<SessionData> => {\n try {\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n },\n storage,\n );\n // validate the existing session and rehydrate and update cookies to the response if necessary\n const existingSession = await authSessionService.validateExistingSession();\n return existingSession;\n } catch (error) {\n logger.error(\"Error validating tokens\", error);\n return { authenticated: false };\n }\n};\n\n// internal - used by all exported functions\n/**\n * Core authentication middleware logic.\n *\n * The Authentication Story:\n * 1. Validate tokens to understand current authentication state\n * 2. Attempt token refresh if needed (the OAuth pipeline approach)\n * 3. Apply route-specific authentication rules based on final state\n */\nconst applyAuth = async (\n authConfig: OptionalAuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n const response = NextResponse.next({\n request, // ensure incoming request headers get propagated\n });\n const cookieConfig = {\n ...authConfigWithDefaults?.cookies?.tokens,\n [UserStorage.USER]: authConfigWithDefaults?.cookies?.user || {},\n };\n logger.debug(\"Incoming request:\", {\n pathName: request.nextUrl.pathname,\n method: request.method,\n });\n const storage = new NextjsMiddlewareCookieStorage(\n cookieConfig,\n request,\n response,\n );\n // check if the incoming path is a system URL\n const shouldSkipAuthForSystemUrlsCheck = shouldSkipAuthForSystemUrls(\n request.nextUrl.pathname,\n authConfigWithDefaults,\n );\n\n // Skip authentication for system URLs (callback, challenge, logout)\n // we don't want to validate the session in this case as this would\n // auto-hydrate and potential conflict with the logic of the api call\n if (shouldSkipAuthForSystemUrlsCheck) {\n return response;\n }\n\n // Step 1: Understand the current authentication state\n const session = await validateAuthTokensIfPresent(\n authConfigWithDefaults,\n storage,\n );\n\n const shouldSkipAuthForRoutePatternsCheck = shouldSkipAuthForRoutePatterns(\n request.nextUrl.pathname,\n authConfigWithDefaults,\n );\n\n // Normalize loginUrl for comparison (remove basePath if present)\n const loginPathWithoutBasePath = removeBasePathFromPath(\n authConfigWithDefaults.loginUrl,\n authConfigWithDefaults.basePath,\n );\n const pathNameIsLoginUrl =\n request.nextUrl.pathname === loginPathWithoutBasePath;\n\n logger.debug(\"Authentication state:\", {\n authenticated: session.authenticated,\n pathName: request.nextUrl.pathname,\n pathNameIsLoginUrl,\n shouldAttemptRefresh: shouldAttemptRefresh(session),\n shouldSkipAuthForSystemUrls: shouldSkipAuthForSystemUrlsCheck,\n shouldSkipAuthForRoutePatterns: shouldSkipAuthForRoutePatternsCheck,\n });\n\n // Step 2: Handle deep link cookie for unauthenticated users using CivicAuth\n // handleDeepLinking automatically detects if we're at loginUrl or a protected route\n // and applies the appropriate logic for each case\n if (!session.authenticated) {\n const civicAuth = new CivicAuth(storage, {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n });\n const originUrl = getOriginUrl(request, authConfigWithDefaults);\n const requestUrl = `${originUrl}${request.nextUrl.pathname}${request.nextUrl.search}${request.nextUrl.hash}`;\n\n await civicAuth.handleDeepLinking(requestUrl, originUrl);\n }\n\n // Step 3: Handle login URL with special logic\n if (pathNameIsLoginUrl) {\n handleLoginUrl(request.nextUrl.pathname, session, authConfigWithDefaults);\n return response; // Always allow access to login URL\n }\n\n // Skip authentication for routes not matching include/exclude patterns\n if (shouldSkipAuthForRoutePatternsCheck) {\n return response;\n }\n\n // Handle unauthenticated users on protected routes\n if (!session.authenticated) {\n return handleUnauthenticatedUser(\n session,\n request,\n response,\n storage,\n authConfigWithDefaults,\n );\n }\n\n // Happy ending - authentication passed\n logger.debug(\"→ Authentication successful, allowing access to\", response.url);\n copyCivicCookies(response, request);\n const authenticatedResponse = NextResponse.next({\n request, // ensure that the cookies get added to the request as well as the response\n });\n copyCivicCookies(response, authenticatedResponse);\n return authenticatedResponse;\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\nconst isRedirectResponse = (response?: NextResponse) =>\n response && response.status === 307;\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 the response is redirected it means that the user is not authenticated\n // so we skip the rest of the custom middleware to redirect to the login page\n if (response && isRedirectResponse(response)) {\n logger.debug(\n \"User is unauthenticated, redirecting to \",\n response.headers.get(\"location\"),\n );\n return response;\n }\n // ensure requests get the cookies in case of redirects\n if (response) {\n copyCivicCookies(response, request);\n }\n const middlewareResponse = await middleware(request);\n\n // we need to ensure that the civic cookies that were potentially\n // added by CivicAuth are set on the final response after all\n // middleware has been run\n if (response) {\n copyCivicCookies(response, middlewareResponse);\n }\n return middlewareResponse;\n };\n };\n}\n"]}
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 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 { SessionData } from \"@/types.js\";\nimport {\n shouldAttemptRefresh,\n shouldSkipAuthForSystemUrls,\n handleLoginUrl,\n shouldSkipAuthForRoutePatterns,\n handleUnauthenticatedUser,\n copyCivicCookies,\n getOriginUrl,\n removeBasePathFromPath,\n} from \"./utils.js\";\nimport { NextjsMiddlewareCookieStorage } from \"./utils.js\";\nimport { UserStorage } from \"@/shared/lib/types.js\";\nimport { CivicAuth } from \"@/server/session.js\";\n\nconst logger = loggers.nextjs.middleware;\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\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 storage: NextjsMiddlewareCookieStorage,\n): Promise<SessionData> => {\n try {\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n },\n storage,\n );\n // validate the existing session and rehydrate and update cookies to the response if necessary\n const existingSession = await authSessionService.validateExistingSession();\n return existingSession;\n } catch (error) {\n logger.error(\"Error validating tokens\", error);\n return { authenticated: false };\n }\n};\n\n// internal - used by all exported functions\n/**\n * Core authentication middleware logic.\n *\n * The Authentication Story:\n * 1. Validate tokens to understand current authentication state\n * 2. Attempt token refresh if needed (the OAuth pipeline approach)\n * 3. Apply route-specific authentication rules based on final state\n */\nconst applyAuth = async (\n authConfig: OptionalAuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n const response = NextResponse.next({\n request, // ensure incoming request headers get propagated\n });\n const cookieConfig = {\n ...authConfigWithDefaults?.cookies?.tokens,\n [UserStorage.USER]: authConfigWithDefaults?.cookies?.user || {},\n };\n logger.debug(\"Incoming request:\", {\n pathName: request.nextUrl.pathname,\n method: request.method,\n });\n const storage = new NextjsMiddlewareCookieStorage(\n cookieConfig,\n request,\n response,\n );\n // check if the incoming path is a system URL\n const shouldSkipAuthForSystemUrlsCheck = shouldSkipAuthForSystemUrls(\n request.nextUrl.pathname,\n authConfigWithDefaults,\n );\n\n // Skip authentication for system URLs (callback, challenge, logout)\n // we don't want to validate the session in this case as this would\n // auto-hydrate and potential conflict with the logic of the api call\n if (shouldSkipAuthForSystemUrlsCheck) {\n return response;\n }\n\n // Step 1: Understand the current authentication state\n const session = await validateAuthTokensIfPresent(\n authConfigWithDefaults,\n storage,\n );\n\n const shouldSkipAuthForRoutePatternsCheck = shouldSkipAuthForRoutePatterns(\n request.nextUrl.pathname,\n authConfigWithDefaults,\n );\n\n // Normalize loginUrl for comparison (remove basePath if present)\n const loginPathWithoutBasePath = removeBasePathFromPath(\n authConfigWithDefaults.loginUrl,\n authConfigWithDefaults.basePath,\n );\n const pathNameIsLoginUrl =\n request.nextUrl.pathname === loginPathWithoutBasePath;\n\n logger.debug(\"Authentication state:\", {\n authenticated: session.authenticated,\n pathName: request.nextUrl.pathname,\n pathNameIsLoginUrl,\n shouldAttemptRefresh: shouldAttemptRefresh(session),\n shouldSkipAuthForSystemUrls: shouldSkipAuthForSystemUrlsCheck,\n shouldSkipAuthForRoutePatterns: shouldSkipAuthForRoutePatternsCheck,\n });\n\n // Skip authentication for routes not matching include/exclude patterns\n // This must happen BEFORE deep linking to prevent capturing excluded paths\n // (e.g., analytics proxy paths like /ga/*, /gtm/*, /ingest/*) as return URLs\n // BUT we still allow the login URL through, as it needs deep linking support\n if (shouldSkipAuthForRoutePatternsCheck && !pathNameIsLoginUrl) {\n return response;\n }\n\n // Step 2: Handle deep link cookie for unauthenticated users using CivicAuth\n // handleDeepLinking automatically detects if we're at loginUrl or a protected route\n // and applies the appropriate logic for each case\n if (!session.authenticated) {\n const civicAuth = new CivicAuth(storage, {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n });\n const originUrl = getOriginUrl(request, authConfigWithDefaults);\n const requestUrl = `${originUrl}${request.nextUrl.pathname}${request.nextUrl.search}${request.nextUrl.hash}`;\n\n await civicAuth.handleDeepLinking(requestUrl, originUrl);\n }\n\n // Step 3: Handle login URL with special logic\n if (pathNameIsLoginUrl) {\n handleLoginUrl(request.nextUrl.pathname, session, authConfigWithDefaults);\n return response; // Always allow access to login URL\n }\n\n // Handle unauthenticated users on protected routes\n if (!session.authenticated) {\n return handleUnauthenticatedUser(\n session,\n request,\n response,\n storage,\n authConfigWithDefaults,\n );\n }\n\n // Happy ending - authentication passed\n logger.debug(\"→ Authentication successful, allowing access to\", response.url);\n copyCivicCookies(response, request);\n const authenticatedResponse = NextResponse.next({\n request, // ensure that the cookies get added to the request as well as the response\n });\n copyCivicCookies(response, authenticatedResponse);\n return authenticatedResponse;\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\nconst isRedirectResponse = (response?: NextResponse) =>\n response && response.status === 307;\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 the response is redirected it means that the user is not authenticated\n // so we skip the rest of the custom middleware to redirect to the login page\n if (response && isRedirectResponse(response)) {\n logger.debug(\n \"User is unauthenticated, redirecting to \",\n response.headers.get(\"location\"),\n );\n return response;\n }\n // ensure requests get the cookies in case of redirects\n if (response) {\n copyCivicCookies(response, request);\n }\n const middlewareResponse = await middleware(request);\n\n // we need to ensure that the civic cookies that were potentially\n // added by CivicAuth are set on the final response after all\n // middleware has been run\n if (response) {\n copyCivicCookies(response, middlewareResponse);\n }\n return middlewareResponse;\n };\n };\n}\n"]}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "@civic/auth:0.13.1";
1
+ export declare const VERSION = "@civic/auth:0.13.2";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // This is an auto-generated file. Do not edit.
2
- export const VERSION = "@civic/auth:0.13.1";
2
+ export const VERSION = "@civic/auth:0.13.2";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,oBAAoB,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.13.1\";\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,oBAAoB,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.13.2\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civic/auth",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -59,8 +59,8 @@
59
59
  "ts-deepmerge": "^7.0.2",
60
60
  "usehooks-ts": "^3.1.0",
61
61
  "uuid": "^10.0.0",
62
- "@civic/iframe-resizer": "0.1.2",
63
- "@civic/auth-verify": "0.0.4"
62
+ "@civic/auth-verify": "0.0.4",
63
+ "@civic/iframe-resizer": "0.1.2"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@rollup/plugin-typescript": "^12.1.1",