@civic/auth 0.11.1 → 0.11.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 +3 -0
- package/dist/nextjs/middleware.d.ts.map +1 -1
- package/dist/nextjs/middleware.js +9 -2
- package/dist/nextjs/middleware.js.map +1 -1
- package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/server/ServerAuthenticationResolver.js +2 -6
- package/dist/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/services/AuthenticationService.d.ts.map +1 -1
- package/dist/services/AuthenticationService.js +2 -2
- package/dist/services/AuthenticationService.js.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.d.ts.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.js +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.js.map +1 -1
- package/dist/shared/lib/util.d.ts +4 -3
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +34 -23
- package/dist/shared/lib/util.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/handlers/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.js +1 -1
- package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -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;AAS9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAK3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,2BACd,sBAAsB,WACrC,6BAA6B,KACrC,OAAO,CAAC,WAAW,CAgBrB,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;AAC9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAK3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,2BACd,sBAAsB,WACrC,6BAA6B,KACrC,OAAO,CAAC,WAAW,CAgBrB,CAAC;AAkGF;;;;;;;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;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,UAAU,GAAE,kBAAuB,gBAExC,UAAU,KACrB,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CA2BrD"}
|
|
@@ -39,7 +39,9 @@ export const validateAuthTokensIfPresent = async (authConfigWithDefaults, storag
|
|
|
39
39
|
*/
|
|
40
40
|
const applyAuth = async (authConfig, request) => {
|
|
41
41
|
const authConfigWithDefaults = resolveAuthConfig(authConfig);
|
|
42
|
-
const response = NextResponse.next(
|
|
42
|
+
const response = NextResponse.next({
|
|
43
|
+
request, // ensure incoming request headers get propagated
|
|
44
|
+
});
|
|
43
45
|
const cookieConfig = {
|
|
44
46
|
...authConfigWithDefaults?.cookies?.tokens,
|
|
45
47
|
[UserStorage.USER]: authConfigWithDefaults?.cookies?.user || {},
|
|
@@ -84,7 +86,12 @@ const applyAuth = async (authConfig, request) => {
|
|
|
84
86
|
}
|
|
85
87
|
// Happy ending - authentication passed
|
|
86
88
|
logger.debug("→ Authentication successful, allowing access to", response.url);
|
|
87
|
-
|
|
89
|
+
copyCivicCookies(response, request);
|
|
90
|
+
const authenticatedResponse = NextResponse.next({
|
|
91
|
+
request, // ensure that the cookies get added to the request as well as the response
|
|
92
|
+
});
|
|
93
|
+
copyCivicCookies(response, authenticatedResponse);
|
|
94
|
+
return authenticatedResponse;
|
|
88
95
|
};
|
|
89
96
|
/**
|
|
90
97
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AAExF,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,8BAA8B,EAC9B,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;AAMzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,sBAA8C,EAC9C,OAAsC,EAChB,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,kBAAkB,GAAG,MAAM,4BAA4B,CAAC,KAAK,CACjE;YACE,GAAG,sBAAsB;YACzB,WAAW,EAAE,sBAAsB,CAAC,WAAW;SAChD,EACD,OAAO,CACR,CAAC;QACF,8FAA8F;QAC9F,MAAM,eAAe,GAAG,MAAM,kBAAkB,CAAC,uBAAuB,EAAE,CAAC;QAC3E,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;AAEF,4CAA4C;AAC5C;;;;;;;GAOG;AACH,MAAM,SAAS,GAAG,KAAK,EACrB,UAA8B,EAC9B,OAAoB,EACe,EAAE;IACrC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,YAAY,GAAG;QACnB,GAAG,sBAAsB,EAAE,OAAO,EAAE,MAAM;QAC1C,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,sBAAsB,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE;KAChE,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,6BAA6B,CAC/C,YAAY,EACZ,OAAO,EACP,QAAQ,CACT,CAAC;IACF,6CAA6C;IAC7C,MAAM,gCAAgC,GAAG,2BAA2B,CAClE,OAAO,CAAC,OAAO,CAAC,QAAQ,EACxB,sBAAsB,CACvB,CAAC;IAEF,oEAAoE;IACpE,mEAAmE;IACnE,qEAAqE;IACrE,IAAI,gCAAgC,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,sDAAsD;IACtD,MAAM,OAAO,GAAG,MAAM,2BAA2B,CAC/C,sBAAsB,EACtB,OAAO,CACR,CAAC;IAEF,MAAM,mCAAmC,GAAG,8BAA8B,CACxE,OAAO,CAAC,OAAO,CAAC,QAAQ,EACxB,sBAAsB,CACvB,CAAC;IACF,MAAM,kBAAkB,GACtB,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,QAAQ,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;QACpC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ;QAClC,kBAAkB;QAClB,oBAAoB,EAAE,oBAAoB,CAAC,OAAO,CAAC;QACnD,2BAA2B,EAAE,gCAAgC;QAC7D,8BAA8B,EAAE,mCAAmC;KACpE,CAAC,CAAC;IAEH,gHAAgH;IAChH,IAAI,kBAAkB,EAAE,CAAC;QACvB,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC;QAC1E,OAAO,QAAQ,CAAC,CAAC,mCAAmC;IACtD,CAAC;IAED,uEAAuE;IACvE,IAAI,mCAAmC,EAAE,CAAC;QACxC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,mDAAmD;IACnD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,yBAAyB,CAC9B,OAAO,EACP,OAAO,EACP,QAAQ,EACR,OAAO,EACP,sBAAsB,CACvB,CAAC;IACJ,CAAC;IAED,uCAAuC;IACvC,MAAM,CAAC,KAAK,CAAC,iDAAiD,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9E,OAAO,QAAQ,CAAC;AAClB,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,MAAM,kBAAkB,GAAG,CAAC,QAAuB,EAAE,EAAE,CACrD,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC;AAEtC;;;;;;;;;;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,4EAA4E;YAC5E,6EAA6E;YAC7E,IAAI,QAAQ,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7C,MAAM,CAAC,KAAK,CACV,0CAA0C,EAC1C,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CACjC,CAAC;gBACF,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,uDAAuD;YACvD,IAAI,QAAQ,EAAE,CAAC;gBACb,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACtC,CAAC;YACD,MAAM,kBAAkB,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;YAErD,iEAAiE;YACjE,6DAA6D;YAC7D,0BAA0B;YAC1B,IAAI,QAAQ,EAAE,CAAC;gBACb,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;YACjD,CAAC;YACD,OAAO,kBAAkB,CAAC;QAC5B,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 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} from \"./utils.js\";\nimport { NextjsMiddlewareCookieStorage } from \"./utils.js\";\nimport { UserStorage } from \"@/shared/lib/types.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 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 const pathNameIsLoginUrl =\n request.nextUrl.pathname === authConfigWithDefaults.loginUrl;\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: Attempt token refresh if needed (the OAuth pipeline approach) // 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 return response;\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} from \"./utils.js\";\nimport { NextjsMiddlewareCookieStorage } from \"./utils.js\";\nimport { UserStorage } from \"@/shared/lib/types.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 const pathNameIsLoginUrl =\n request.nextUrl.pathname === authConfigWithDefaults.loginUrl;\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: Attempt token refresh if needed (the OAuth pipeline approach) // 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerAuthenticationResolver.d.ts","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQrD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,qBAAqB,CAAC;AAMhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAK7D,qBAAa,4BAA6B,YAAW,sBAAsB;IAMvE,QAAQ,CAAC,UAAU,EAAE,UAAU;IAC/B,QAAQ,CAAC,OAAO,EAAE,WAAW;IAC7B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IAPjD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO;IAeP;;;;OAIG;IACG,gBAAgB,CACpB,WAAW,EAAE,WAAW,GAAG,IAAI,GAC9B,OAAO,CAAC,WAAW,CAAC;IAqDvB;;;OAGG;IACG,uBAAuB,CAC3B,kBAAkB,UAAO,GACxB,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ServerAuthenticationResolver.d.ts","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQrD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,qBAAqB,CAAC;AAMhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAK7D,qBAAa,4BAA6B,YAAW,sBAAsB;IAMvE,QAAQ,CAAC,UAAU,EAAE,UAAU;IAC/B,QAAQ,CAAC,OAAO,EAAE,WAAW;IAC7B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IAPjD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO;IAeP;;;;OAIG;IACG,gBAAgB,CACpB,WAAW,EAAE,WAAW,GAAG,IAAI,GAC9B,OAAO,CAAC,WAAW,CAAC;IAqDvB;;;OAGG;IACG,uBAAuB,CAC3B,kBAAkB,UAAO,GACxB,OAAO,CAAC,WAAW,CAAC;IA0DvB,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBrB,aAAa,CACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,CAAC;IA0C3B,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc7C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;WAOxC,KAAK,CAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,aAAa,EACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GACrC,OAAO,CAAC,sBAAsB,CAAC;CAUnC"}
|
|
@@ -85,9 +85,6 @@ export class ServerAuthenticationResolver {
|
|
|
85
85
|
// TODO: investigate a more peformant way to validate a server session
|
|
86
86
|
// other than using JWKS and JWT verification which is what validateOauth2Tokens uses
|
|
87
87
|
const sessionData = await this.getSessionData();
|
|
88
|
-
logger.debug("validateExistingSession", {
|
|
89
|
-
disableRefresh: this.authConfig.disableRefresh,
|
|
90
|
-
});
|
|
91
88
|
// If we don't have an ID token, try to refresh if we have a refresh token
|
|
92
89
|
// Access token is no longer required for authentication
|
|
93
90
|
if (!sessionData?.idToken) {
|
|
@@ -112,7 +109,7 @@ export class ServerAuthenticationResolver {
|
|
|
112
109
|
id_token: sessionData.idToken, // Always required
|
|
113
110
|
refresh_token: sessionData.refreshToken,
|
|
114
111
|
oidc_session_expires_at: sessionData.oidcSessionExpiresAt,
|
|
115
|
-
}, this.
|
|
112
|
+
}, this.authConfig);
|
|
116
113
|
return sessionData;
|
|
117
114
|
}
|
|
118
115
|
catch (error) {
|
|
@@ -161,8 +158,7 @@ export class ServerAuthenticationResolver {
|
|
|
161
158
|
}
|
|
162
159
|
// exchange auth code for tokens
|
|
163
160
|
const tokens = await exchangeTokens(code, state, this.pkceProducer, this.oauth2client, // clean up types here to avoid the ! operator
|
|
164
|
-
this.
|
|
165
|
-
this.authConfig.clientSecret);
|
|
161
|
+
this.authConfig);
|
|
166
162
|
await storeServerTokens(this.storage, tokens);
|
|
167
163
|
// Store user data in cookie (like VanillaJS implementation does)
|
|
168
164
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerAuthenticationResolver.js","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport type {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport {\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeServerTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport type { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { getUser, getUserFromTokens } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport type { CookieStorage } from \"@/shared/lib/storage.js\";\nimport { AuthenticationRefresherImpl } from \"@/shared/lib/AuthenticationRefresherImpl.js\";\n\nconst logger = loggers.services.validation;\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer | null;\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n readonly authConfig: AuthConfig,\n readonly storage: AuthStorage,\n readonly endpointOverrides?: Partial<Endpoints>,\n ) {\n // Determine if PKCE should be used based on config\n // Default to true\n const usePkce = authConfig.pkce !== false;\n\n // Only create PKCE producer if we're using PKCE\n this.pkceProducer = usePkce\n ? new GenericPublicClientPKCEProducer(storage)\n : null;\n }\n\n /**\n * Attempts to refresh tokens if a refresh token is available\n * @param sessionData Current session data\n * @returns Updated session data\n */\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n logger.debug(\"tryRefreshTokens\", { sessionData });\n // If there's a refresh token, attempt to refresh tokens\n if (sessionData?.refreshToken) {\n const authRefresher = await AuthenticationRefresherImpl.build(\n {\n ...this.authConfig,\n oauthServer: this.authConfig.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n this.storage,\n async (error) => {\n logger.error(\n \"ServerAuthenticationResolver: Error refreshing tokens\",\n { error },\n );\n return Promise.reject(error);\n },\n this.endpointOverrides,\n );\n const tokenResponseBody = await authRefresher.refreshAccessToken();\n if (!tokenResponseBody) {\n throw new Error(\"No tokens returned from refresh\");\n }\n // Store user data if a user can be derived from the tokens\n try {\n const user = await getUserFromTokens(tokenResponseBody);\n if (user) {\n const userSession = new GenericUserSession(this.storage);\n await userSession.set(user);\n logger.debug(\"User cookie stored successfully\", {\n hasUser: !!user,\n });\n } else {\n logger.warn(\"No user found after token exchange\");\n }\n } catch (error) {\n logger.error(\"Failed to store user cookie:\", error);\n }\n // Construct a refreshed session with the new tokens\n return {\n authenticated: true,\n idToken: tokenResponseBody.id_token,\n accessToken: tokenResponseBody.access_token,\n refreshToken: tokenResponseBody.refresh_token,\n oidcSessionExpiresAt: tokenResponseBody.oidc_session_expires_at,\n wasRehydrated: true,\n };\n }\n\n // No refresh token available\n return { ...sessionData, authenticated: false };\n }\n\n /**\n * returns The session data if the session is valid, otherwise an unauthenticated session\n * @returns {Promise<SessionData>}\n */\n async validateExistingSession(\n attemptRehydration = true,\n ): Promise<SessionData> {\n // TODO: investigate a more peformant way to validate a server session\n // other than using JWKS and JWT verification which is what validateOauth2Tokens uses\n const sessionData = await this.getSessionData();\n\n logger.debug(\"validateExistingSession\", {\n disableRefresh: this.authConfig.disableRefresh,\n });\n // If we don't have an ID token, try to refresh if we have a refresh token\n // Access token is no longer required for authentication\n if (!sessionData?.idToken) {\n if (attemptRehydration && !this.authConfig.disableRefresh) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n }\n\n return { ...sessionData, authenticated: false };\n }\n\n // Initialize if needed\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"JWKS endpoint not found\");\n }\n\n try {\n // Validate existing tokens - access token validation happens only if it exists\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken, // May be undefined\n id_token: sessionData.idToken, // Always required\n refresh_token: sessionData.refreshToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.endpoints.jwks,\n this.oauth2client!,\n this.oauthServer,\n );\n return sessionData;\n } catch (error) {\n logger.warn(\"Error validating tokens\", { error });\n if (attemptRehydration && !this.authConfig.disableRefresh) {\n // If token validation fails, try to refresh tokens\n try {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n } catch (error) {\n logger.error(\"Error refreshing tokens after validation failure\", {\n error,\n });\n return { ...sessionData, authenticated: false };\n }\n }\n\n return { ...sessionData, authenticated: false };\n }\n }\n\n get oauthServer(): string {\n return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async init(): Promise<this> {\n // Ensure clientId is present for OAuth operations\n if (!this.authConfig.clientId) {\n throw new Error(\"clientId is required for OAuth server operations\");\n }\n\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n\n // Check if we're using PKCE and validate code verifier if needed\n if (this.pkceProducer) {\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n }\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n this.authConfig.clientSecret,\n );\n\n await storeServerTokens(this.storage, tokens);\n\n // Store user data in cookie (like VanillaJS implementation does)\n try {\n const user = await getUser(this.storage);\n if (user) {\n const userSession = new GenericUserSession(this.storage);\n await userSession.set(user);\n logger.debug(\"User cookie stored successfully\", { hasUser: !!user });\n } else {\n logger.warn(\"No user found after token exchange\");\n }\n } catch (error) {\n logger.error(\"Failed to store user cookie:\", error);\n // Don't throw - tokens are already stored, this is just for client-side convenience\n }\n\n // the code verifier should be single-use, so we delete it if using PKCE\n if (this.pkceProducer) {\n await this.storage.delete(CodeVerifier.COOKIE_NAME);\n }\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token, // User is authenticated if they have an ID token\n idToken: storageData.id_token,\n accessToken: storageData.access_token, // Optional\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints.endsession;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: CookieStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationResolver> {\n const resolver = new ServerAuthenticationResolver(\n authConfig,\n storage,\n endpointOverrides,\n );\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ServerAuthenticationResolver.js","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQ3C,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAE1F,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;AAE3C,MAAM,OAAO,4BAA4B;IAM5B;IACA;IACA;IAPH,YAAY,CAAsB;IAClC,YAAY,CAA2B;IACvC,SAAS,CAAwB;IAEzC,YACW,UAAsB,EACtB,OAAoB,EACpB,iBAAsC;QAFtC,eAAU,GAAV,UAAU,CAAY;QACtB,YAAO,GAAP,OAAO,CAAa;QACpB,sBAAiB,GAAjB,iBAAiB,CAAqB;QAE/C,mDAAmD;QACnD,kBAAkB;QAClB,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,CAAC;QAE1C,gDAAgD;QAChD,IAAI,CAAC,YAAY,GAAG,OAAO;YACzB,CAAC,CAAC,IAAI,+BAA+B,CAAC,OAAO,CAAC;YAC9C,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,gBAAgB,CACpB,WAA+B;QAE/B,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QAClD,wDAAwD;QACxD,IAAI,WAAW,EAAE,YAAY,EAAE,CAAC;YAC9B,MAAM,aAAa,GAAG,MAAM,2BAA2B,CAAC,KAAK,CAC3D;gBACE,GAAG,IAAI,CAAC,UAAU;gBAClB,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW,IAAI,mBAAmB;aAChE,EACD,IAAI,CAAC,OAAO,EACZ,KAAK,EAAE,KAAK,EAAE,EAAE;gBACd,MAAM,CAAC,KAAK,CACV,uDAAuD,EACvD,EAAE,KAAK,EAAE,CACV,CAAC;gBACF,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC,EACD,IAAI,CAAC,iBAAiB,CACvB,CAAC;YACF,MAAM,iBAAiB,GAAG,MAAM,aAAa,CAAC,kBAAkB,EAAE,CAAC;YACnE,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACrD,CAAC;YACD,2DAA2D;YAC3D,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;gBACxD,IAAI,IAAI,EAAE,CAAC;oBACT,MAAM,WAAW,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzD,MAAM,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC5B,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;wBAC9C,OAAO,EAAE,CAAC,CAAC,IAAI;qBAChB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACtD,CAAC;YACD,oDAAoD;YACpD,OAAO;gBACL,aAAa,EAAE,IAAI;gBACnB,OAAO,EAAE,iBAAiB,CAAC,QAAQ;gBACnC,WAAW,EAAE,iBAAiB,CAAC,YAAY;gBAC3C,YAAY,EAAE,iBAAiB,CAAC,aAAa;gBAC7C,oBAAoB,EAAE,iBAAiB,CAAC,uBAAuB;gBAC/D,aAAa,EAAE,IAAI;aACpB,CAAC;QACJ,CAAC;QAED,6BAA6B;QAC7B,OAAO,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,uBAAuB,CAC3B,kBAAkB,GAAG,IAAI;QAEzB,sEAAsE;QACtE,qFAAqF;QACrF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAEhD,0EAA0E;QAC1E,wDAAwD;QACxD,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC;YAC1B,IAAI,kBAAkB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;gBAC1D,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;gBACtE,IAAI,oBAAoB,CAAC,aAAa,EAAE,CAAC;oBACvC,OAAO,oBAAoB,CAAC;gBAC9B,CAAC;YACH,CAAC;YAED,OAAO,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QAED,uBAAuB;QACvB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAEnE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,CAAC;YACH,+EAA+E;YAC/E,MAAM,oBAAoB,CACxB;gBACE,YAAY,EAAE,WAAW,CAAC,WAAW,EAAE,mBAAmB;gBAC1D,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,kBAAkB;gBACjD,aAAa,EAAE,WAAW,CAAC,YAAY;gBACvC,uBAAuB,EAAE,WAAW,CAAC,oBAAoB;aAC1D,EACD,IAAI,CAAC,UAAU,CAChB,CAAC;YACF,OAAO,WAAW,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,IAAI,kBAAkB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;gBAC1D,mDAAmD;gBACnD,IAAI,CAAC;oBACH,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;oBACtE,IAAI,oBAAoB,CAAC,aAAa,EAAE,CAAC;wBACvC,OAAO,oBAAoB,CAAC;oBAC9B,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,CAAC,kDAAkD,EAAE;wBAC/D,KAAK;qBACN,CAAC,CAAC;oBACH,OAAO,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;gBAClD,CAAC;YACH,CAAC;YAED,OAAO,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,IAAI,mBAAmB,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,IAAI;QACR,kDAAkD;QAClD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QAED,uBAAuB;QACvB,IAAI,CAAC,SAAS,GAAG,MAAM,yBAAyB,CAC9C,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,iBAAiB,CACvB,CAAC;QACF,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAClC,IAAI,CAAC,UAAU,CAAC,QAAQ,EACxB,IAAI,CAAC,SAAS,CAAC,IAAI,EACnB,IAAI,CAAC,SAAS,CAAC,KAAK,EACpB;YACE,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW;SACzC,CACF,CAAC;QAEF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,IAAY,EACZ,KAAa;QAEb,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAE1C,iEAAiE;QACjE,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC;YAC/D,IAAI,CAAC,YAAY;gBAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC3E,CAAC;QAED,gCAAgC;QAChC,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,IAAI,EACJ,KAAK,EACL,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,YAAa,EAAE,8CAA8C;QAClE,IAAI,CAAC,UAAU,CAChB,CAAC;QAEF,MAAM,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE9C,iEAAiE;QACjE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzC,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,WAAW,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACzD,MAAM,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC5B,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACvE,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACpD,oFAAoF;QACtF,CAAC;QAED,wEAAwE;QACxE,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvD,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAE9B,OAAO;YACL,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,iDAAiD;YACxF,OAAO,EAAE,WAAW,CAAC,QAAQ;YAC7B,WAAW,EAAE,WAAW,CAAC,YAAY,EAAE,WAAW;YAClD,YAAY,EAAE,WAAW,CAAC,aAAa;YACvC,oBAAoB,EAAE,WAAW,CAAC,uBAAuB;SAC1D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,qBAAqB;QACzB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;IACnC,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,KAAK,CAChB,UAAsB,EACtB,OAAsB,EACtB,iBAAsC;QAEtC,MAAM,QAAQ,GAAG,IAAI,4BAA4B,CAC/C,UAAU,EACV,OAAO,EACP,iBAAiB,CAClB,CAAC;QACF,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEtB,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF","sourcesContent":["import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport type {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport {\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeServerTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport type { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { getUser, getUserFromTokens } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport type { CookieStorage } from \"@/shared/lib/storage.js\";\nimport { AuthenticationRefresherImpl } from \"@/shared/lib/AuthenticationRefresherImpl.js\";\n\nconst logger = loggers.services.validation;\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer | null;\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n readonly authConfig: AuthConfig,\n readonly storage: AuthStorage,\n readonly endpointOverrides?: Partial<Endpoints>,\n ) {\n // Determine if PKCE should be used based on config\n // Default to true\n const usePkce = authConfig.pkce !== false;\n\n // Only create PKCE producer if we're using PKCE\n this.pkceProducer = usePkce\n ? new GenericPublicClientPKCEProducer(storage)\n : null;\n }\n\n /**\n * Attempts to refresh tokens if a refresh token is available\n * @param sessionData Current session data\n * @returns Updated session data\n */\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n logger.debug(\"tryRefreshTokens\", { sessionData });\n // If there's a refresh token, attempt to refresh tokens\n if (sessionData?.refreshToken) {\n const authRefresher = await AuthenticationRefresherImpl.build(\n {\n ...this.authConfig,\n oauthServer: this.authConfig.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n this.storage,\n async (error) => {\n logger.error(\n \"ServerAuthenticationResolver: Error refreshing tokens\",\n { error },\n );\n return Promise.reject(error);\n },\n this.endpointOverrides,\n );\n const tokenResponseBody = await authRefresher.refreshAccessToken();\n if (!tokenResponseBody) {\n throw new Error(\"No tokens returned from refresh\");\n }\n // Store user data if a user can be derived from the tokens\n try {\n const user = await getUserFromTokens(tokenResponseBody);\n if (user) {\n const userSession = new GenericUserSession(this.storage);\n await userSession.set(user);\n logger.debug(\"User cookie stored successfully\", {\n hasUser: !!user,\n });\n } else {\n logger.warn(\"No user found after token exchange\");\n }\n } catch (error) {\n logger.error(\"Failed to store user cookie:\", error);\n }\n // Construct a refreshed session with the new tokens\n return {\n authenticated: true,\n idToken: tokenResponseBody.id_token,\n accessToken: tokenResponseBody.access_token,\n refreshToken: tokenResponseBody.refresh_token,\n oidcSessionExpiresAt: tokenResponseBody.oidc_session_expires_at,\n wasRehydrated: true,\n };\n }\n\n // No refresh token available\n return { ...sessionData, authenticated: false };\n }\n\n /**\n * returns The session data if the session is valid, otherwise an unauthenticated session\n * @returns {Promise<SessionData>}\n */\n async validateExistingSession(\n attemptRehydration = true,\n ): Promise<SessionData> {\n // TODO: investigate a more peformant way to validate a server session\n // other than using JWKS and JWT verification which is what validateOauth2Tokens uses\n const sessionData = await this.getSessionData();\n\n // If we don't have an ID token, try to refresh if we have a refresh token\n // Access token is no longer required for authentication\n if (!sessionData?.idToken) {\n if (attemptRehydration && !this.authConfig.disableRefresh) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n }\n\n return { ...sessionData, authenticated: false };\n }\n\n // Initialize if needed\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"JWKS endpoint not found\");\n }\n\n try {\n // Validate existing tokens - access token validation happens only if it exists\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken, // May be undefined\n id_token: sessionData.idToken, // Always required\n refresh_token: sessionData.refreshToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.authConfig,\n );\n return sessionData;\n } catch (error) {\n logger.warn(\"Error validating tokens\", { error });\n if (attemptRehydration && !this.authConfig.disableRefresh) {\n // If token validation fails, try to refresh tokens\n try {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n } catch (error) {\n logger.error(\"Error refreshing tokens after validation failure\", {\n error,\n });\n return { ...sessionData, authenticated: false };\n }\n }\n\n return { ...sessionData, authenticated: false };\n }\n }\n\n get oauthServer(): string {\n return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async init(): Promise<this> {\n // Ensure clientId is present for OAuth operations\n if (!this.authConfig.clientId) {\n throw new Error(\"clientId is required for OAuth server operations\");\n }\n\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n\n // Check if we're using PKCE and validate code verifier if needed\n if (this.pkceProducer) {\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n }\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.authConfig,\n );\n\n await storeServerTokens(this.storage, tokens);\n\n // Store user data in cookie (like VanillaJS implementation does)\n try {\n const user = await getUser(this.storage);\n if (user) {\n const userSession = new GenericUserSession(this.storage);\n await userSession.set(user);\n logger.debug(\"User cookie stored successfully\", { hasUser: !!user });\n } else {\n logger.warn(\"No user found after token exchange\");\n }\n } catch (error) {\n logger.error(\"Failed to store user cookie:\", error);\n // Don't throw - tokens are already stored, this is just for client-side convenience\n }\n\n // the code verifier should be single-use, so we delete it if using PKCE\n if (this.pkceProducer) {\n await this.storage.delete(CodeVerifier.COOKIE_NAME);\n }\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token, // User is authenticated if they have an ID token\n idToken: storageData.id_token,\n accessToken: storageData.access_token, // Optional\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints.endsession;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: CookieStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationResolver> {\n const resolver = new ServerAuthenticationResolver(\n authConfig,\n storage,\n endpointOverrides,\n );\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationService.d.ts","sourceRoot":"","sources":["../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"AuthenticationService.d.ts","sourceRoot":"","sources":["../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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"}
|
|
@@ -313,7 +313,7 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
|
|
|
313
313
|
throw new Error("Code verifier not found in storage");
|
|
314
314
|
// exchange auth code for tokens
|
|
315
315
|
const tokens = await exchangeTokens(code, state, this.pkceProducer, this.oauth2client, // clean up types here to avoid the ! operator
|
|
316
|
-
this.
|
|
316
|
+
this.config);
|
|
317
317
|
await this.storeTokensOnLogin(tokens);
|
|
318
318
|
// cleanup the browser window if needed
|
|
319
319
|
const parsedDisplayMode = displayModeFromState(state, this.config.displayMode);
|
|
@@ -424,7 +424,7 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
|
|
|
424
424
|
refresh_token: sessionData.refreshToken,
|
|
425
425
|
access_token: sessionData.accessToken,
|
|
426
426
|
oidc_session_expires_at: sessionData.oidcSessionExpiresAt,
|
|
427
|
-
}, this.
|
|
427
|
+
}, this.config);
|
|
428
428
|
return sessionData;
|
|
429
429
|
}
|
|
430
430
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationService.js","sourceRoot":"","sources":["../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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","sourcesContent":["// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport type {\n DisplayMode,\n Endpoints,\n FrameworkType,\n LoginAppDesignOptions,\n LoginPostMessage,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport {\n BrowserPublicClientPKCEProducer,\n ConfidentialClientPKCEConsumer,\n} from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { getVersion } from \"@/shared/index.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport type {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n} from \"@/services/types.js\";\nimport { PopupError } from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil.js\";\nimport {\n DEFAULT_AUTH_SERVER,\n DEFAULT_OAUTH_GET_PARAMS,\n LOGOUT_STATE,\n} from \"@/constants.js\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage.js\";\nimport { getUser } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport {\n getIframeRef,\n iframeIsVisible,\n isEmbeddedIframeMode,\n} from \"@/shared/lib/iframeUtils.js\";\nimport { v4 as uuid } from \"uuid\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { BrowserAuthenticationRefresher } from \"@/shared/lib/BrowserAuthenticationRefresher.js\";\nimport { collectAndSendSDKAnalytics } from \"@/lib/analytics.js\";\n\nconst clearStorageAndEmitSignOut = async () => {\n const localStorage = new LocalStorageAdapter();\n await clearTokens(localStorage);\n await clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n};\n\nexport type GenericAuthenticationInitiatorConfig = {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // Optional PKCE challenge - not needed for confidential clients using client secrets\n pkceConsumer?: PKCEConsumer;\n};\n\nexport type BrowserAuthenticationInitiatorConfig = Omit<\n GenericAuthenticationInitiatorConfig,\n \"state\"\n> & {\n logoutUrl?: string;\n logoutRedirectUrl: string;\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n // Optional iframe display mode - modal (full-screen overlay) or embedded (within container)\n iframeDisplayMode?: \"modal\" | \"embedded\";\n // Optional base path for routing in case app is served from a subdirectory\n basePath?: string;\n // Optional URL to redirect to after login success\n loginSuccessUrl?: string;\n // Framework being used (for analytics)\n framework?: FrameworkType;\n // Whether to automatically switch to redirect mode when browser doesn't support iframe-based auth\n autoRedirect?: boolean;\n};\n\nconst defaultSetDesignOptions = (value: LoginAppDesignOptions) => {\n localStorage.setItem(\"loginAppDesign\", JSON.stringify(value));\n};\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n private postMessageHandler: null | ((event: MessageEvent) => void) = null;\n\n protected config: BrowserAuthenticationInitiatorConfig;\n static browserCorsFailsSilentlyRedirectUrl: string;\n private _iframeRef: HTMLIFrameElement | null = null;\n\n public setDisplayMode(displayMode: DisplayMode) {\n this.config.displayMode = displayMode;\n }\n\n get displayMode() {\n return this.config.displayMode;\n }\n\n get isServerTokenExchange() {\n return this.config.pkceConsumer instanceof ConfidentialClientPKCEConsumer;\n }\n get state() {\n return generateState({\n displayMode: this.config.displayMode,\n iframeDisplayMode: this.config.iframeDisplayMode,\n serverTokenExchange: this.isServerTokenExchange,\n loginSuccessUrl: this.config.loginSuccessUrl,\n framework: this.config.framework,\n sdkVersion: getVersion(),\n });\n }\n public instanceId: string;\n public browserCorsFailsSilentlyRedirectUrl: string = \"\";\n\n constructor(\n config: typeof this.config,\n readonly setDesignOptions = defaultSetDesignOptions,\n ) {\n this.instanceId = uuid();\n this.config = config;\n\n this.postMessageHandler = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n event.origin.endsWith(\"civic.com\") ||\n thisURL.hostname === \"localhost\"\n ) {\n if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {\n return;\n }\n const loginMessage = event.data as LoginPostMessage;\n if (loginMessage.type === \"generatePopupFailed\") {\n this.handleLoginAppPopupFailed(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (\n loginMessage.type === \"browserCorsFailsSilently\" &&\n this.displayMode === \"iframe\"\n ) {\n this.handleBrowserCorsFailsSilently(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (loginMessage.type === \"design\") {\n // TODO handle the design message\n this.handleLoginAppDesignUpdate(\n loginMessage.data as LoginAppDesignOptions,\n );\n return;\n }\n }\n };\n\n window.addEventListener(\"message\", this.postMessageHandler);\n }\n\n async handleLoginAppPopupFailed(redirectUrl: string) {\n console.warn(\n \"Login app popup failed open a popup, using redirect mode instead...\",\n redirectUrl,\n );\n window.location.href = redirectUrl;\n }\n\n async handleBrowserCorsFailsSilently(redirectUrl: string) {\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl =\n redirectUrl;\n // Check autoRedirect config before proceeding\n if (this.config.autoRedirect !== false && iframeIsVisible()) {\n // hide the iframe as we're in redirect mode\n // to avoid it loading then immediately disappearing\n const iframe = document.getElementById(\n \"civic-auth-iframe-container\",\n ) as HTMLIFrameElement | null;\n if (iframe) {\n iframe.style.display = \"none\";\n }\n return this.handleUserInteractionBrowserCorsFailsSilently();\n }\n }\n\n async handleUserInteractionBrowserCorsFailsSilently(): Promise<{\n isRedirecting: boolean;\n }> {\n const isInEmbeddedIframeMode = isEmbeddedIframeMode();\n // check if the iframe is visible\n if (\n !isInEmbeddedIframeMode &&\n this.config.autoRedirect !== false && // Add this check\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl\n ) {\n console.warn(\n \"Browser CORS failed silently, redirecting...\",\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl,\n );\n this.config.displayMode = \"redirect\";\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n const signInUrl = await this.getSignInUrl();\n window.dispatchEvent(\n new CustomEvent(\"locationWillChange\", {\n detail: { newUrl: signInUrl.toString() },\n }),\n );\n setTimeout(() => {\n window.location.href = signInUrl.toString();\n }, 100);\n return { isRedirecting: true };\n }\n return { isRedirecting: false };\n }\n\n async handleLoginAppDesignUpdate(options: LoginAppDesignOptions) {\n this.setDesignOptions(options);\n }\n\n async getSignInUrl(): Promise<URL> {\n const val = await generateOauthLoginUrl({\n ...this.config,\n state: this.state,\n });\n return val;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n // Send SDK analytics when authentication starts\n // Fire and forget - don't block authentication if analytics fails\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n\n const url = await this.getSignInUrl();\n\n if (this.config.displayMode === \"iframe\") {\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n }\n\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n // TODO handle the 'onclose' event to clean up and reset the authStatus\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n async signOut(\n idToken: string | undefined,\n iframeRef: HTMLIFrameElement | null,\n ): Promise<URL> {\n let url;\n const localStorage = new LocalStorageAdapter();\n const state = this.state;\n if (this.isServerTokenExchange) {\n if (!this.config.logoutUrl) {\n throw new Error(\"logoutUrl is required for server token exchange\");\n }\n url = new URL(this.config.logoutUrl, window.location.origin);\n url.searchParams.append(\"state\", state);\n } else {\n if (!idToken) {\n throw new Error(\"idToken is required for non-server token exchange\");\n }\n\n url = await generateOauthLogoutUrl({\n ...this.config,\n idToken,\n state,\n redirectUrl: this.config.logoutRedirectUrl,\n });\n }\n\n if (this.config.displayMode === \"iframe\") {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n await localStorage.delete(LOGOUT_STATE);\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n\n LocalStorageAdapter.emitter.emit(\"signOut\");\n }\n\n if (this.config.displayMode === \"redirect\") {\n // we don't clear any storage here as we're redirecting to the logout url\n // and the server should handle that\n await localStorage.set(LOGOUT_STATE, state);\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n cleanup() {\n if (this.postMessageHandler) {\n window.removeEventListener(\"message\", this.postMessageHandler);\n }\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: GenericAuthenticationInitiatorConfig;\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(idToken: string): Promise<URL> {\n return generateOauthLogoutUrl({\n ...this.config,\n idToken,\n });\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n logoutUrl?: string;\n logoutRedirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n super({\n ...config,\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n async storeTokensOnLogin(tokens: OIDCTokenResponseBody) {\n const clientStorage = new LocalStorageAdapter();\n await storeTokens(clientStorage, tokens);\n // delete code verifier as it should be single-use\n await clientStorage.delete(CodeVerifier.COOKIE_NAME);\n const user = await getUser(clientStorage);\n if (!user) {\n throw new Error(\"Failed to get user info\");\n }\n const userSession = new GenericUserSession(clientStorage);\n await userSession.set(user);\n LocalStorageAdapter.emitter.emit(\"signIn\");\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n await this.storeTokensOnLogin(tokens);\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.addEventListener(\"beforeunload\", () => {\n window?.opener?.focus();\n });\n window.close();\n }\n // these are the default oAuth params that get added to the URL in redirect which we want to remove if present\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(new LocalStorageAdapter());\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n // If token validation fails but we have a refresh token, attempt to refresh\n if (sessionData?.refreshToken) {\n try {\n const clientStorage = new LocalStorageAdapter();\n\n // Create a BrowserAuthenticationRefresher to handle token refresh using the build method\n const authConfig = {\n clientId: this.config.clientId,\n oauthServer: this.oauthServer,\n redirectUrl: this.config.redirectUrl,\n };\n\n // Use build method which handles initialization\n const refresher = await BrowserAuthenticationRefresher.build(\n authConfig,\n clientStorage,\n async (error: Error) => {\n console.warn(\"Failed to refresh tokens during validation\", error);\n },\n this.config.endpointOverrides,\n );\n\n try {\n // Perform token refresh (no need to call init explicitly)\n const tokenResponse = await refresher.refreshAccessToken();\n\n // For backend flows, tokenResponse might be null since tokens are in HTTP-only cookies\n if (tokenResponse) {\n // Store tokens for SPA flows where tokens are accessible\n await this.storeTokensOnLogin(tokenResponse);\n }\n\n // Return a new session with the refreshed tokens\n const refreshedSession = await this.getSessionData();\n if (refreshedSession && refreshedSession.authenticated) {\n return {\n ...refreshedSession,\n authenticated: true,\n };\n } else {\n throw new Error(\"Failed to get refreshed session data\");\n }\n } catch (refreshApiError) {\n console.error(\n \"Error during token refresh API call:\",\n refreshApiError,\n );\n throw refreshApiError; // Re-throw to be caught by outer catch block\n }\n } catch (error) {\n const refreshError = error as Error;\n console.error(\"Token refresh failed with error:\", refreshError);\n // Only delete refresh token if it's invalid, not for network errors\n // which might be temporary\n if (\n refreshError.message.includes(\"invalid\") ||\n refreshError.message.includes(\"expired\")\n ) {\n const clientStorage = new LocalStorageAdapter();\n console.log(\"Deleting invalid refresh token\");\n await clearTokens(clientStorage);\n await clearUser(clientStorage);\n }\n console.warn(\"Failed to refresh tokens\", refreshError);\n }\n }\n\n return {\n ...sessionData,\n authenticated: false,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n return unAuthenticatedSession;\n }\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"No jwks endpoint\");\n }\n\n // this function will throw if the idToken is invalid\n // Note: Access token is no longer required for authentication\n await validateOauth2Tokens(\n {\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n access_token: sessionData.accessToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.endpoints.jwks,\n this.oauth2client!,\n this.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n const storage = new LocalStorageAdapter();\n await clearTokens(storage);\n await clearUser(storage);\n return unAuthenticatedSession;\n }\n }\n\n get oauthServer(): string {\n return this.config.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints?.endsession;\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AuthenticationService.js","sourceRoot":"","sources":["../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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","sourcesContent":["// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport type {\n DisplayMode,\n Endpoints,\n FrameworkType,\n LoginAppDesignOptions,\n LoginPostMessage,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport {\n BrowserPublicClientPKCEProducer,\n ConfidentialClientPKCEConsumer,\n} from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { getVersion } from \"@/shared/index.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport type {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n} from \"@/services/types.js\";\nimport { PopupError } from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil.js\";\nimport {\n DEFAULT_AUTH_SERVER,\n DEFAULT_OAUTH_GET_PARAMS,\n LOGOUT_STATE,\n} from \"@/constants.js\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage.js\";\nimport { getUser } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport {\n getIframeRef,\n iframeIsVisible,\n isEmbeddedIframeMode,\n} from \"@/shared/lib/iframeUtils.js\";\nimport { v4 as uuid } from \"uuid\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { BrowserAuthenticationRefresher } from \"@/shared/lib/BrowserAuthenticationRefresher.js\";\nimport { collectAndSendSDKAnalytics } from \"@/lib/analytics.js\";\n\nconst clearStorageAndEmitSignOut = async () => {\n const localStorage = new LocalStorageAdapter();\n await clearTokens(localStorage);\n await clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n};\n\nexport type GenericAuthenticationInitiatorConfig = {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // Optional PKCE challenge - not needed for confidential clients using client secrets\n pkceConsumer?: PKCEConsumer;\n};\n\nexport type BrowserAuthenticationInitiatorConfig = Omit<\n GenericAuthenticationInitiatorConfig,\n \"state\"\n> & {\n logoutUrl?: string;\n logoutRedirectUrl: string;\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n // Optional iframe display mode - modal (full-screen overlay) or embedded (within container)\n iframeDisplayMode?: \"modal\" | \"embedded\";\n // Optional base path for routing in case app is served from a subdirectory\n basePath?: string;\n // Optional URL to redirect to after login success\n loginSuccessUrl?: string;\n // Framework being used (for analytics)\n framework?: FrameworkType;\n // Whether to automatically switch to redirect mode when browser doesn't support iframe-based auth\n autoRedirect?: boolean;\n};\n\nconst defaultSetDesignOptions = (value: LoginAppDesignOptions) => {\n localStorage.setItem(\"loginAppDesign\", JSON.stringify(value));\n};\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n private postMessageHandler: null | ((event: MessageEvent) => void) = null;\n\n protected config: BrowserAuthenticationInitiatorConfig;\n static browserCorsFailsSilentlyRedirectUrl: string;\n private _iframeRef: HTMLIFrameElement | null = null;\n\n public setDisplayMode(displayMode: DisplayMode) {\n this.config.displayMode = displayMode;\n }\n\n get displayMode() {\n return this.config.displayMode;\n }\n\n get isServerTokenExchange() {\n return this.config.pkceConsumer instanceof ConfidentialClientPKCEConsumer;\n }\n get state() {\n return generateState({\n displayMode: this.config.displayMode,\n iframeDisplayMode: this.config.iframeDisplayMode,\n serverTokenExchange: this.isServerTokenExchange,\n loginSuccessUrl: this.config.loginSuccessUrl,\n framework: this.config.framework,\n sdkVersion: getVersion(),\n });\n }\n public instanceId: string;\n public browserCorsFailsSilentlyRedirectUrl: string = \"\";\n\n constructor(\n config: typeof this.config,\n readonly setDesignOptions = defaultSetDesignOptions,\n ) {\n this.instanceId = uuid();\n this.config = config;\n\n this.postMessageHandler = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n event.origin.endsWith(\"civic.com\") ||\n thisURL.hostname === \"localhost\"\n ) {\n if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {\n return;\n }\n const loginMessage = event.data as LoginPostMessage;\n if (loginMessage.type === \"generatePopupFailed\") {\n this.handleLoginAppPopupFailed(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (\n loginMessage.type === \"browserCorsFailsSilently\" &&\n this.displayMode === \"iframe\"\n ) {\n this.handleBrowserCorsFailsSilently(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (loginMessage.type === \"design\") {\n // TODO handle the design message\n this.handleLoginAppDesignUpdate(\n loginMessage.data as LoginAppDesignOptions,\n );\n return;\n }\n }\n };\n\n window.addEventListener(\"message\", this.postMessageHandler);\n }\n\n async handleLoginAppPopupFailed(redirectUrl: string) {\n console.warn(\n \"Login app popup failed open a popup, using redirect mode instead...\",\n redirectUrl,\n );\n window.location.href = redirectUrl;\n }\n\n async handleBrowserCorsFailsSilently(redirectUrl: string) {\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl =\n redirectUrl;\n // Check autoRedirect config before proceeding\n if (this.config.autoRedirect !== false && iframeIsVisible()) {\n // hide the iframe as we're in redirect mode\n // to avoid it loading then immediately disappearing\n const iframe = document.getElementById(\n \"civic-auth-iframe-container\",\n ) as HTMLIFrameElement | null;\n if (iframe) {\n iframe.style.display = \"none\";\n }\n return this.handleUserInteractionBrowserCorsFailsSilently();\n }\n }\n\n async handleUserInteractionBrowserCorsFailsSilently(): Promise<{\n isRedirecting: boolean;\n }> {\n const isInEmbeddedIframeMode = isEmbeddedIframeMode();\n // check if the iframe is visible\n if (\n !isInEmbeddedIframeMode &&\n this.config.autoRedirect !== false && // Add this check\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl\n ) {\n console.warn(\n \"Browser CORS failed silently, redirecting...\",\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl,\n );\n this.config.displayMode = \"redirect\";\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n const signInUrl = await this.getSignInUrl();\n window.dispatchEvent(\n new CustomEvent(\"locationWillChange\", {\n detail: { newUrl: signInUrl.toString() },\n }),\n );\n setTimeout(() => {\n window.location.href = signInUrl.toString();\n }, 100);\n return { isRedirecting: true };\n }\n return { isRedirecting: false };\n }\n\n async handleLoginAppDesignUpdate(options: LoginAppDesignOptions) {\n this.setDesignOptions(options);\n }\n\n async getSignInUrl(): Promise<URL> {\n const val = await generateOauthLoginUrl({\n ...this.config,\n state: this.state,\n });\n return val;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n // Send SDK analytics when authentication starts\n // Fire and forget - don't block authentication if analytics fails\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n\n const url = await this.getSignInUrl();\n\n if (this.config.displayMode === \"iframe\") {\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n }\n\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n // TODO handle the 'onclose' event to clean up and reset the authStatus\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n async signOut(\n idToken: string | undefined,\n iframeRef: HTMLIFrameElement | null,\n ): Promise<URL> {\n let url;\n const localStorage = new LocalStorageAdapter();\n const state = this.state;\n if (this.isServerTokenExchange) {\n if (!this.config.logoutUrl) {\n throw new Error(\"logoutUrl is required for server token exchange\");\n }\n url = new URL(this.config.logoutUrl, window.location.origin);\n url.searchParams.append(\"state\", state);\n } else {\n if (!idToken) {\n throw new Error(\"idToken is required for non-server token exchange\");\n }\n\n url = await generateOauthLogoutUrl({\n ...this.config,\n idToken,\n state,\n redirectUrl: this.config.logoutRedirectUrl,\n });\n }\n\n if (this.config.displayMode === \"iframe\") {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n await localStorage.delete(LOGOUT_STATE);\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n\n LocalStorageAdapter.emitter.emit(\"signOut\");\n }\n\n if (this.config.displayMode === \"redirect\") {\n // we don't clear any storage here as we're redirecting to the logout url\n // and the server should handle that\n await localStorage.set(LOGOUT_STATE, state);\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n cleanup() {\n if (this.postMessageHandler) {\n window.removeEventListener(\"message\", this.postMessageHandler);\n }\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: GenericAuthenticationInitiatorConfig;\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(idToken: string): Promise<URL> {\n return generateOauthLogoutUrl({\n ...this.config,\n idToken,\n });\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n logoutUrl?: string;\n logoutRedirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n super({\n ...config,\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n async storeTokensOnLogin(tokens: OIDCTokenResponseBody) {\n const clientStorage = new LocalStorageAdapter();\n await storeTokens(clientStorage, tokens);\n // delete code verifier as it should be single-use\n await clientStorage.delete(CodeVerifier.COOKIE_NAME);\n const user = await getUser(clientStorage);\n if (!user) {\n throw new Error(\"Failed to get user info\");\n }\n const userSession = new GenericUserSession(clientStorage);\n await userSession.set(user);\n LocalStorageAdapter.emitter.emit(\"signIn\");\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.config,\n );\n await this.storeTokensOnLogin(tokens);\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.addEventListener(\"beforeunload\", () => {\n window?.opener?.focus();\n });\n window.close();\n }\n // these are the default oAuth params that get added to the URL in redirect which we want to remove if present\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(new LocalStorageAdapter());\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n // If token validation fails but we have a refresh token, attempt to refresh\n if (sessionData?.refreshToken) {\n try {\n const clientStorage = new LocalStorageAdapter();\n\n // Create a BrowserAuthenticationRefresher to handle token refresh using the build method\n const authConfig = {\n clientId: this.config.clientId,\n oauthServer: this.oauthServer,\n redirectUrl: this.config.redirectUrl,\n };\n\n // Use build method which handles initialization\n const refresher = await BrowserAuthenticationRefresher.build(\n authConfig,\n clientStorage,\n async (error: Error) => {\n console.warn(\"Failed to refresh tokens during validation\", error);\n },\n this.config.endpointOverrides,\n );\n\n try {\n // Perform token refresh (no need to call init explicitly)\n const tokenResponse = await refresher.refreshAccessToken();\n\n // For backend flows, tokenResponse might be null since tokens are in HTTP-only cookies\n if (tokenResponse) {\n // Store tokens for SPA flows where tokens are accessible\n await this.storeTokensOnLogin(tokenResponse);\n }\n\n // Return a new session with the refreshed tokens\n const refreshedSession = await this.getSessionData();\n if (refreshedSession && refreshedSession.authenticated) {\n return {\n ...refreshedSession,\n authenticated: true,\n };\n } else {\n throw new Error(\"Failed to get refreshed session data\");\n }\n } catch (refreshApiError) {\n console.error(\n \"Error during token refresh API call:\",\n refreshApiError,\n );\n throw refreshApiError; // Re-throw to be caught by outer catch block\n }\n } catch (error) {\n const refreshError = error as Error;\n console.error(\"Token refresh failed with error:\", refreshError);\n // Only delete refresh token if it's invalid, not for network errors\n // which might be temporary\n if (\n refreshError.message.includes(\"invalid\") ||\n refreshError.message.includes(\"expired\")\n ) {\n const clientStorage = new LocalStorageAdapter();\n console.log(\"Deleting invalid refresh token\");\n await clearTokens(clientStorage);\n await clearUser(clientStorage);\n }\n console.warn(\"Failed to refresh tokens\", refreshError);\n }\n }\n\n return {\n ...sessionData,\n authenticated: false,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n return unAuthenticatedSession;\n }\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"No jwks endpoint\");\n }\n\n // this function will throw if the idToken is invalid\n // Note: Access token is no longer required for authentication\n await validateOauth2Tokens(\n {\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n access_token: sessionData.accessToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.config,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n const storage = new LocalStorageAdapter();\n await clearTokens(storage);\n await clearUser(storage);\n return unAuthenticatedSession;\n }\n }\n\n get oauthServer(): string {\n return this.config.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints?.endsession;\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationRefresherImpl.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/AuthenticationRefresherImpl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AASrD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAGrF,qBAAa,2BAA4B,SAAQ,8BAA8B;IAO3E,SAAS,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IANlD,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,YAAY,CAA2B;gBAE7C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,YAAA;IAQ5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;WAyBd,KAAK,CAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GACrC,OAAO,CAAC,2BAA2B,CAAC;IAYjC,WAAW,CACf,iBAAiB,EAAE,qBAAqB,GAAG,IAAI,GAC9C,OAAO,CAAC,IAAI,CAAC;IAcV,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"AuthenticationRefresherImpl.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/AuthenticationRefresherImpl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AASrD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAGrF,qBAAa,2BAA4B,SAAQ,8BAA8B;IAO3E,SAAS,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IANlD,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,YAAY,CAA2B;gBAE7C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,YAAA;IAQ5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;WAyBd,KAAK,CAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GACrC,OAAO,CAAC,2BAA2B,CAAC;IAYjC,WAAW,CACf,iBAAiB,EAAE,qBAAqB,GAAG,IAAI,GAC9C,OAAO,CAAC,IAAI,CAAC;IAcV,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;CAyClE"}
|
|
@@ -67,7 +67,7 @@ export class AuthenticationRefresherImpl extends GenericAuthenticationRefresher
|
|
|
67
67
|
const tokenResponseBody = (await oauth2Client.refreshAccessToken(refreshToken, refreshOptions));
|
|
68
68
|
// Validate the refreshed tokens - ID token is the primary token
|
|
69
69
|
// Access token validation is now optional
|
|
70
|
-
await validateOauth2Tokens(tokenResponseBody, this.
|
|
70
|
+
await validateOauth2Tokens(tokenResponseBody, this.authConfig);
|
|
71
71
|
await this.storeTokens(tokenResponseBody);
|
|
72
72
|
return tokenResponseBody;
|
|
73
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationRefresherImpl.js","sourceRoot":"","sources":["../../../src/shared/lib/AuthenticationRefresherImpl.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"AuthenticationRefresherImpl.js","sourceRoot":"","sources":["../../../src/shared/lib/AuthenticationRefresherImpl.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthConfig } from \"@/server/config.js\";\nimport {\n clearTokens,\n clearUser,\n getEndpointsWithOverrides,\n storeServerTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport type { AuthStorage, Endpoints, OIDCTokenResponseBody } from \"@/types.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { GenericAuthenticationRefresher } from \"./GenericAuthenticationRefresher.js\";\nimport { loggers } from \"@/lib/logger.js\";\n\nexport class AuthenticationRefresherImpl extends GenericAuthenticationRefresher {\n private endpoints: Endpoints | undefined;\n private oauth2client: OAuth2Client | undefined;\n constructor(\n authConfig: AuthConfig,\n storage: AuthStorage,\n onError: (error: Error) => Promise<void>,\n protected endpointOverrides?: Partial<Endpoints>,\n ) {\n super(onError);\n this.authConfig = authConfig;\n this.storage = storage;\n this.init();\n }\n\n async init(): Promise<this> {\n if (!this.authConfig) throw new Error(\"No auth config available\");\n\n // Ensure clientId is present for OAuth operations\n if (!this.authConfig.clientId) {\n throw new Error(\"clientId is required for OAuth refresh operations\");\n }\n\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n onError: (error: Error) => Promise<void>,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationRefresherImpl> {\n const refresher = new AuthenticationRefresherImpl(\n authConfig,\n storage,\n onError,\n endpointOverrides,\n );\n await refresher.init();\n\n return refresher;\n }\n\n async storeTokens(\n tokenResponseBody: OIDCTokenResponseBody | null,\n ): Promise<void> {\n if (!this.storage) throw new Error(\"No storage available\");\n // For null tokenResponseBody, we skip storage since tokens might be managed elsewhere (e.g., HTTP-only cookies)\n if (!tokenResponseBody) return;\n\n if (this.storage.storageType === \"cookie\") {\n loggers.services.refresh.info(\"Storing tokens in server-side storage\");\n await storeServerTokens(this.storage, tokenResponseBody);\n return;\n }\n loggers.services.refresh.info(\"Storing tokens in non-cookie storage\");\n await storeTokens(this.storage, tokenResponseBody);\n }\n\n async refreshAccessToken(): Promise<OIDCTokenResponseBody | null> {\n if (!this.storage) throw new Error(\"No storage available\");\n\n // this will throw if no refresh token is available\n const refreshToken = await this.getRefreshToken();\n if (!this.oauth2client) {\n await this.init();\n }\n if (!this.endpoints?.jwks) {\n throw new Error(\"No jwks endpoint\");\n }\n try {\n const oauth2Client = this.oauth2client!;\n\n const refreshOptions: Record<string, string> = {};\n if (this.authConfig?.clientSecret) {\n refreshOptions.credentials = this.authConfig.clientSecret;\n refreshOptions.authenticateWith = \"request_body\";\n }\n\n const tokenResponseBody = (await oauth2Client.refreshAccessToken(\n refreshToken,\n refreshOptions,\n )) as OIDCTokenResponseBody;\n\n // Validate the refreshed tokens - ID token is the primary token\n // Access token validation is now optional\n await validateOauth2Tokens(tokenResponseBody, this.authConfig!);\n\n await this.storeTokens(tokenResponseBody);\n return tokenResponseBody;\n } catch (error) {\n console.warn(\n \"OAuth server refresh call failed, clearing tokens and user\",\n error,\n );\n await clearTokens(this.storage);\n await clearUser(this.storage);\n throw new Error(`Token refresh failed: ${(error as Error).message}`);\n }\n }\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import type { AuthStorage, Endpoints, OIDCTokenResponseBody, ParsedTokens } from
|
|
|
2
2
|
import { OAuth2Client } from "oslo/oauth2";
|
|
3
3
|
import type { PKCEConsumer, PKCEProducer } from "../../services/types.js";
|
|
4
4
|
import type { CookieStorage } from "./storage.js";
|
|
5
|
-
import type { BackendEndpoints } from "../../server/config.js";
|
|
5
|
+
import type { AuthConfig, BackendEndpoints } from "../../server/config.js";
|
|
6
6
|
/**
|
|
7
7
|
* Given a PKCE code verifier, derive the code challenge using SHA
|
|
8
8
|
*/
|
|
@@ -27,7 +27,7 @@ export declare function generateOauthLogoutUrl(config: {
|
|
|
27
27
|
endpointOverrides?: Partial<Endpoints>;
|
|
28
28
|
}): Promise<URL>;
|
|
29
29
|
export declare function buildOauth2Client(clientId: string, redirectUri: string, endpoints: Endpoints): OAuth2Client;
|
|
30
|
-
export declare function exchangeTokens(code: string, state: string, pkceProducer: PKCEProducer | null, oauth2Client: OAuth2Client,
|
|
30
|
+
export declare function exchangeTokens(code: string, state: string, pkceProducer: PKCEProducer | null, oauth2Client: OAuth2Client, authConfig: ValidationConfig): Promise<OIDCTokenResponseBody>;
|
|
31
31
|
/**
|
|
32
32
|
* Calculates the maxAge values for access and refresh token cookies
|
|
33
33
|
* based on the TTL values in the access token
|
|
@@ -54,7 +54,8 @@ export declare function clearAuthServerSession(storage: AuthStorage): Promise<vo
|
|
|
54
54
|
export declare function clearUser(storage: AuthStorage): Promise<void>;
|
|
55
55
|
export declare function retrieveTokens(storage: AuthStorage): Promise<Partial<OIDCTokenResponseBody> | null>;
|
|
56
56
|
export declare function retrieveOidcSessionExpiredAtSeconds(storage: AuthStorage): Promise<number | null>;
|
|
57
|
-
export
|
|
57
|
+
export type ValidationConfig = Pick<AuthConfig, "clientId" | "oauthServer" | "oauthServerBaseUrl" | "clientSecret">;
|
|
58
|
+
export declare function validateOauth2Tokens(tokens: OIDCTokenResponseBody, config: ValidationConfig): Promise<ParsedTokens>;
|
|
58
59
|
/**
|
|
59
60
|
* Get backend endpoints with default values merged with custom configuration
|
|
60
61
|
* @param backendEndpoints - Optional custom backend endpoints configuration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,YAAY,EACb,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/util.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/lib/util.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { AUTH_SERVER_LEGACY_SESSION, AUTH_SERVER_SESSION, OAuthTokenTypes, } from "./types.js";
|
|
2
2
|
import { OAuth2Client } from "oslo/oauth2";
|
|
3
|
-
import {
|
|
4
|
-
import * as jose from "jose";
|
|
3
|
+
import { addSlashIfNeeded, getOauthEndpoints } from "../../lib/oauth.js";
|
|
5
4
|
import { withoutUndefined } from "../../utils.js";
|
|
6
5
|
import { GenericUserSession } from "../../shared/lib/UserSession.js";
|
|
7
6
|
import { decodeJwt } from "jose";
|
|
8
7
|
import { AUTOREFRESH_TIMEOUT_NAME, LOGOUT_STATE, MAX_COOKIE_AGE_SECONDS, REFRESH_IN_PROGRESS, } from "../../constants.js";
|
|
9
8
|
import { loggers } from "../../lib/logger.js";
|
|
9
|
+
import { verify } from "@civic/auth-verify";
|
|
10
10
|
const logger = loggers.services.validation;
|
|
11
11
|
/**
|
|
12
12
|
* Given a PKCE code verifier, derive the code challenge using SHA
|
|
@@ -68,13 +68,13 @@ export function buildOauth2Client(clientId, redirectUri, endpoints) {
|
|
|
68
68
|
redirectURI: redirectUri,
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
-
export async function exchangeTokens(code, state, pkceProducer, oauth2Client,
|
|
71
|
+
export async function exchangeTokens(code, state, pkceProducer, oauth2Client, authConfig) {
|
|
72
72
|
// Get code verifier if using PKCE
|
|
73
73
|
const codeVerifier = pkceProducer
|
|
74
74
|
? await pkceProducer.getCodeVerifier()
|
|
75
75
|
: null;
|
|
76
76
|
// Ensure at least one authentication method is provided
|
|
77
|
-
if (!codeVerifier && !clientSecret) {
|
|
77
|
+
if (!codeVerifier && !authConfig.clientSecret) {
|
|
78
78
|
throw new Error("Either PKCE code verifier or client secret must be provided");
|
|
79
79
|
}
|
|
80
80
|
// Build options for validateAuthorizationCode
|
|
@@ -82,14 +82,14 @@ export async function exchangeTokens(code, state, pkceProducer, oauth2Client, oa
|
|
|
82
82
|
if (codeVerifier) {
|
|
83
83
|
validationOptions.codeVerifier = codeVerifier;
|
|
84
84
|
}
|
|
85
|
-
if (clientSecret) {
|
|
86
|
-
validationOptions.credentials = clientSecret;
|
|
85
|
+
if (authConfig.clientSecret) {
|
|
86
|
+
validationOptions.credentials = authConfig.clientSecret;
|
|
87
87
|
validationOptions.authenticateWith = "request_body"; // Use client_secret_post method
|
|
88
88
|
}
|
|
89
89
|
const tokens = (await oauth2Client.validateAuthorizationCode(code, validationOptions));
|
|
90
90
|
// Validate relevant tokens
|
|
91
91
|
try {
|
|
92
|
-
await validateOauth2Tokens(tokens,
|
|
92
|
+
await validateOauth2Tokens(tokens, authConfig);
|
|
93
93
|
}
|
|
94
94
|
catch (error) {
|
|
95
95
|
console.error("tokenExchange error", { error, tokens });
|
|
@@ -273,30 +273,41 @@ export async function retrieveOidcSessionExpiredAtSeconds(storage) {
|
|
|
273
273
|
const expiresAt = Number(valueSeconds);
|
|
274
274
|
return isNaN(expiresAt) ? null : expiresAt;
|
|
275
275
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
export async function validateOauth2Tokens(tokens, jwksEndpoint, oauth2Client, issuer) {
|
|
280
|
-
// Only create a new JWKS instance if one doesn't exist yet
|
|
281
|
-
if (!cachedJWKS || cachedJwksUrl !== jwksEndpoint) {
|
|
282
|
-
cachedJWKS = jose.createRemoteJWKSet(new URL(jwksEndpoint));
|
|
283
|
-
cachedJwksUrl = jwksEndpoint;
|
|
284
|
-
}
|
|
276
|
+
export async function validateOauth2Tokens(tokens, config) {
|
|
277
|
+
const baseIssuer = addSlashIfNeeded((config.oauthServer || config.oauthServerBaseUrl) ??
|
|
278
|
+
"https://auth.civic.com/oauth/");
|
|
285
279
|
// Validate the ID token - this is now the primary token for authentication
|
|
286
|
-
const
|
|
287
|
-
issuer:
|
|
288
|
-
|
|
280
|
+
const idTokenVerifyOptions = {
|
|
281
|
+
issuer: baseIssuer,
|
|
282
|
+
};
|
|
283
|
+
// Set audience for ID token
|
|
284
|
+
if (config.clientId) {
|
|
285
|
+
// ID tokens should have the client ID as audience for proper OIDC compliance
|
|
286
|
+
idTokenVerifyOptions.aud = config.clientId;
|
|
287
|
+
}
|
|
288
|
+
logger.debug(`Verifying id_token with options:`, {
|
|
289
|
+
idTokenVerifyOptions,
|
|
290
|
+
config,
|
|
289
291
|
});
|
|
292
|
+
// Use the @civic/auth-verify package for ID token verification
|
|
293
|
+
const idTokenPayload = await verify(tokens.id_token, idTokenVerifyOptions);
|
|
290
294
|
// Only validate the access token if it exists, but if present it must be valid
|
|
291
295
|
let accessTokenPayload;
|
|
292
296
|
if (tokens.access_token) {
|
|
293
|
-
const
|
|
294
|
-
issuer:
|
|
297
|
+
const accessTokenVerifyOptions = {
|
|
298
|
+
issuer: baseIssuer,
|
|
299
|
+
// Access tokens have "civic" as audience based on auth server configuration
|
|
300
|
+
aud: "civic",
|
|
301
|
+
clientId: config.clientId,
|
|
302
|
+
};
|
|
303
|
+
logger.debug(`Verifying access_token with options:`, {
|
|
304
|
+
accessTokenVerifyOptions,
|
|
295
305
|
});
|
|
296
|
-
|
|
306
|
+
// Use the @civic/auth-verify package for access token verification
|
|
307
|
+
accessTokenPayload = await verify(tokens.access_token, accessTokenVerifyOptions);
|
|
297
308
|
}
|
|
298
309
|
return withoutUndefined({
|
|
299
|
-
id_token:
|
|
310
|
+
id_token: idTokenPayload,
|
|
300
311
|
access_token: accessTokenPayload,
|
|
301
312
|
...(tokens?.refresh_token ? { refresh_token: tokens.refresh_token } : {}),
|
|
302
313
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/shared/lib/util.ts"],"names":[],"mappings":"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","sourcesContent":["// Utility functions shared by auth server and client integrations\n// Typically these functions should be used inside AuthenticationInitiator and AuthenticationResolver implementations\nimport type {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n ParsedTokens,\n} from \"@/types.js\";\nimport {\n AUTH_SERVER_LEGACY_SESSION,\n AUTH_SERVER_SESSION,\n OAuthTokenTypes,\n} from \"./types.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { getIssuerVariations, getOauthEndpoints } from \"@/lib/oauth.js\";\nimport * as jose from \"jose\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport type { PKCEConsumer, PKCEProducer } from \"@/services/types.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { decodeJwt, type JWTPayload } from \"jose\";\nimport type { CookieStorage } from \"./storage.js\";\nimport {\n AUTOREFRESH_TIMEOUT_NAME,\n LOGOUT_STATE,\n MAX_COOKIE_AGE_SECONDS,\n REFRESH_IN_PROGRESS,\n} from \"@/constants.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport type { BackendEndpoints } from \"@/server/config.js\";\n\nconst logger = loggers.services.validation;\n/**\n * Given a PKCE code verifier, derive the code challenge using SHA\n */\nexport async function deriveCodeChallenge(\n codeVerifier: string,\n method: \"Plain\" | \"S256\" = \"S256\",\n): Promise<string> {\n if (method === \"Plain\") {\n console.warn(\"Using insecure plain code challenge method\");\n return codeVerifier;\n }\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport async function getEndpointsWithOverrides(\n oauthServer: string,\n endpointOverrides: Partial<Endpoints> = {},\n): Promise<Endpoints> {\n const endpoints = await getOauthEndpoints(oauthServer);\n return {\n ...endpoints,\n ...endpointOverrides,\n };\n}\n\nexport async function generateOauthLoginUrl(config: {\n clientId: string;\n scopes: string[];\n state: string;\n redirectUrl: string;\n oauthServer: string;\n nonce?: string;\n endpointOverrides?: Partial<Endpoints>;\n // Optional PKCE challenge - not needed for confidential clients using client secrets\n pkceConsumer?: PKCEConsumer;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state: config.state,\n scopes: config.scopes,\n });\n\n // Only add PKCE parameters if a pkceConsumer is provided\n if (config.pkceConsumer) {\n const challenge = await config.pkceConsumer.getCodeChallenge();\n // The OAuth2 client supports PKCE, but does not allow passing in a code challenge from some other source\n // It only allows passing in a code verifier which it then hashes itself.\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n }\n\n if (config.nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", config.nonce);\n }\n // Required by the auth server for offline_access scope\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n\n return oAuthUrl;\n}\n\nexport async function generateOauthLogoutUrl(config: {\n clientId: string;\n redirectUrl: string;\n idToken: string;\n state: string;\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const endSessionUrl = new URL(endpoints.endsession);\n endSessionUrl.searchParams.append(\"client_id\", config.clientId);\n endSessionUrl.searchParams.append(\"id_token_hint\", config.idToken);\n endSessionUrl.searchParams.append(\"state\", config.state);\n endSessionUrl.searchParams.append(\n \"post_logout_redirect_uri\",\n config.redirectUrl,\n );\n return endSessionUrl;\n}\n\nexport function buildOauth2Client(\n clientId: string,\n redirectUri: string,\n endpoints: Endpoints,\n): OAuth2Client {\n return new OAuth2Client(clientId, endpoints.auth, endpoints.token, {\n redirectURI: redirectUri,\n });\n}\n\nexport async function exchangeTokens(\n code: string,\n state: string,\n pkceProducer: PKCEProducer | null,\n oauth2Client: OAuth2Client,\n oauthServer: string,\n endpoints: Endpoints,\n clientSecret?: string,\n) {\n // Get code verifier if using PKCE\n const codeVerifier = pkceProducer\n ? await pkceProducer.getCodeVerifier()\n : null;\n\n // Ensure at least one authentication method is provided\n if (!codeVerifier && !clientSecret) {\n throw new Error(\n \"Either PKCE code verifier or client secret must be provided\",\n );\n }\n\n // Build options for validateAuthorizationCode\n const validationOptions: Record<string, string> = {};\n\n if (codeVerifier) {\n validationOptions.codeVerifier = codeVerifier;\n }\n\n if (clientSecret) {\n validationOptions.credentials = clientSecret;\n validationOptions.authenticateWith = \"request_body\"; // Use client_secret_post method\n }\n\n const tokens = (await oauth2Client.validateAuthorizationCode(\n code,\n validationOptions,\n )) as OIDCTokenResponseBody;\n\n // Validate relevant tokens\n try {\n await validateOauth2Tokens(\n tokens,\n endpoints.jwks,\n oauth2Client,\n oauthServer,\n );\n } catch (error) {\n console.error(\"tokenExchange error\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n return tokens;\n}\n/**\n * Calculates the maxAge values for access and refresh token cookies\n * based on the TTL values in the access token\n *\n * maxAge needs to be in seconds from now until expiration\n *\n * @param tokens OIDC tokens response containing the access token\n * @returns Object with accessTokenMaxAge and refreshTokenMaxAge in seconds\n */\nexport const getCookiesMaxAge = (\n tokens: OIDCTokenResponseBody,\n): { idTokenMaxAge: number; accessTokenMaxAge: number } => {\n const DEFAULT_TTL = 60 * 60; // 1 hour default\n\n let idTokenMaxAge = DEFAULT_TTL;\n let accessTokenMaxAge = DEFAULT_TTL;\n\n // The ID token takes priority, as it represents the OIDC session\n if (tokens.id_token) {\n // If no access token exists, try to get expiration from ID token\n const parsedIdToken = decodeJwt(tokens.id_token);\n if (parsedIdToken?.exp) {\n const now = Math.floor(Date.now() / 1000);\n idTokenMaxAge = parsedIdToken.exp - now;\n }\n }\n\n if (tokens.access_token) {\n // Get access token TTL from the token if it exists\n const parsedAccessToken = decodeJwt(tokens.access_token);\n accessTokenMaxAge =\n Number(parsedAccessToken?.accessTokenTTL) || DEFAULT_TTL;\n\n // If access token has exp claim, use that directly\n if (parsedAccessToken?.exp) {\n const now = Math.floor(Date.now() / 1000);\n accessTokenMaxAge = parsedAccessToken.exp - now;\n }\n }\n\n return {\n accessTokenMaxAge,\n idTokenMaxAge,\n };\n};\n\nexport async function setOidcSessionExpiresAt(\n storage: AuthStorage | CookieStorage,\n tokens: OIDCTokenResponseBody,\n) {\n const now = Math.floor(Date.now() / 1000);\n const { idTokenMaxAge } = getCookiesMaxAge(tokens);\n // The OIDC session expiry is linked to the ID token expiry, since this is primarily an OIDC client.\n await storage.set(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n (idTokenMaxAge + now).toString(),\n );\n}\n\nexport async function storeTokens(\n storage: AuthStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // ID token is the primary token and must always be stored\n await storage.set(OAuthTokenTypes.ID_TOKEN, tokens.id_token);\n\n // Only store access token if it exists (no longer required)\n if (tokens.access_token) {\n await storage.set(OAuthTokenTypes.ACCESS_TOKEN, tokens.access_token);\n }\n\n // Store refresh token if it exists\n if (tokens.refresh_token) {\n await storage.set(OAuthTokenTypes.REFRESH_TOKEN, tokens.refresh_token);\n }\n\n // Still set access token expiration even if no access token\n // (will get expiration from ID token in this case)\n await setOidcSessionExpiresAt(storage, tokens);\n}\n\n/**\n * Stores tokens in server-side cookies with appropriate expiration times\n * Uses TTL values from the tokens to set cookie maxAge values\n * Refresh token is set with 400 day expiry\n */\nexport async function storeServerTokens(\n storage: AuthStorage | CookieStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // Get maxAge values based on token TTLs (refresh token TTL will be undefined)\n const now = Math.floor(Date.now() / 1000);\n const { idTokenMaxAge, accessTokenMaxAge } = getCookiesMaxAge(tokens);\n\n // The OIDC session expiry is linked to the ID token expiry, since this is primarily an OIDC client.\n const oidcSessionExpiresAt = now + idTokenMaxAge;\n const cookieStorage = storage as CookieStorage;\n\n // Apply maxAge to cookie options\n const accessTokenCookieOptions = {\n maxAge: accessTokenMaxAge,\n };\n\n const refreshTokenCookieOptions = {\n maxAge: MAX_COOKIE_AGE_SECONDS,\n };\n\n // ID token is always stored (primary authentication token)\n await cookieStorage.set(OAuthTokenTypes.ID_TOKEN, tokens.id_token, {\n maxAge: idTokenMaxAge,\n });\n\n // Access token is optional - only set if it exists\n if (tokens.access_token) {\n await cookieStorage.set(\n OAuthTokenTypes.ACCESS_TOKEN,\n tokens.access_token,\n accessTokenCookieOptions,\n );\n }\n\n // Set refresh token if present with 400 day expiry\n if (tokens.refresh_token) {\n await cookieStorage.set(\n OAuthTokenTypes.REFRESH_TOKEN,\n tokens.refresh_token,\n refreshTokenCookieOptions,\n );\n }\n\n // Still store the access token expiration timestamp even if no access token\n await storage.set(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n oidcSessionExpiresAt.toString(),\n {\n // This is primarily an OIDC client, so we use the ID token max age for the session timeout / refresh scheduling.\n maxAge: idTokenMaxAge,\n },\n );\n logger.debug(\"storeServerTokens\", {\n oidcSessionExpiresAt,\n refreshTokenMaxAge: MAX_COOKIE_AGE_SECONDS,\n idTokenMaxAge,\n hasAccessToken: !!tokens.access_token,\n });\n}\n\nexport async function clearTokens(storage: AuthStorage | CookieStorage) {\n // clear all local storage keys related to OAuth and CivicAuth SDK\n const clearOAuthPromises = [\n ...Object.values(OAuthTokenTypes),\n REFRESH_IN_PROGRESS,\n AUTOREFRESH_TIMEOUT_NAME,\n LOGOUT_STATE,\n ].map(async (key) => {\n await storage.delete(key);\n });\n await Promise.all([...clearOAuthPromises]);\n}\n\nexport async function clearAuthServerSession(storage: AuthStorage) {\n await storage.delete(AUTH_SERVER_SESSION);\n await storage.delete(AUTH_SERVER_LEGACY_SESSION);\n}\n\nexport async function clearUser(storage: AuthStorage) {\n const userSession = new GenericUserSession(storage);\n await userSession.clear();\n}\n\n/**\n * Smart token unwrapping for Safari's base64-encoding bug\n * Only unwraps tokens that are:\n * 1. Base64-encoded (Safari bug) - very long strings without dots\n * 2. Contain a JSON object with a 'value' property that's a valid JWT\n *\n * Does NOT unwrap React Router's normal {value: \"token\"} objects\n */\nfunction unwrapSafariTokenIfNeeded(token: string | null): string | null {\n if (!token) return token;\n\n // Safari-specific detection: base64-encoded JSON that's extremely long\n // Normal wrapped objects from React Router are much shorter and have different characteristics\n if (token && !token.includes(\".\") && token.length > 800) {\n try {\n // Try to decode as base64 and parse as JSON\n const decoded = JSON.parse(atob(token));\n\n // Verify this is Safari's bug: wrapped value must be a valid 3-part JWT\n if (\n decoded &&\n typeof decoded === \"object\" &&\n decoded.value &&\n typeof decoded.value === \"string\" &&\n decoded.value.split(\".\").length === 3\n ) {\n return decoded.value;\n }\n } catch (error) {\n console.error(\"HERE UTIL - SAFARI TOKEN UNWRAP FAILED\", error);\n }\n }\n\n return token;\n}\n\nexport async function retrieveTokens(\n storage: AuthStorage,\n): Promise<Partial<OIDCTokenResponseBody> | null> {\n const idToken = await storage.get(OAuthTokenTypes.ID_TOKEN);\n const accessToken = await storage.get(OAuthTokenTypes.ACCESS_TOKEN);\n const refreshToken = await storage.get(OAuthTokenTypes.REFRESH_TOKEN);\n const oidcSessionExpiresAt = await storage.get(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n );\n\n return {\n id_token: unwrapSafariTokenIfNeeded(idToken) ?? undefined,\n access_token: unwrapSafariTokenIfNeeded(accessToken) ?? undefined,\n refresh_token: unwrapSafariTokenIfNeeded(refreshToken) ?? undefined,\n oidc_session_expires_at:\n oidcSessionExpiresAt !== null\n ? parseInt(oidcSessionExpiresAt, 10)\n : undefined, // Convert string to number\n };\n}\n\nexport async function retrieveOidcSessionExpiredAtSeconds(\n storage: AuthStorage,\n): Promise<number | null> {\n const valueSeconds = await storage.get(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n );\n if (!valueSeconds) {\n return null;\n }\n const expiresAt = Number(valueSeconds);\n return isNaN(expiresAt) ? null : expiresAt;\n}\n\n// Single JWKS instance that persists for the lifetime of the SDK session\nlet cachedJWKS: ReturnType<typeof jose.createRemoteJWKSet> | null = null;\nlet cachedJwksUrl: string | null = null;\n\nexport async function validateOauth2Tokens(\n tokens: OIDCTokenResponseBody,\n jwksEndpoint: string,\n oauth2Client: OAuth2Client,\n issuer: string,\n): Promise<ParsedTokens> {\n // Only create a new JWKS instance if one doesn't exist yet\n if (!cachedJWKS || cachedJwksUrl !== jwksEndpoint) {\n cachedJWKS = jose.createRemoteJWKSet(new URL(jwksEndpoint));\n cachedJwksUrl = jwksEndpoint;\n }\n\n // Validate the ID token - this is now the primary token for authentication\n const idTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.id_token,\n cachedJWKS,\n {\n issuer: getIssuerVariations(issuer),\n audience: oauth2Client.clientId,\n },\n );\n\n // Only validate the access token if it exists, but if present it must be valid\n let accessTokenPayload;\n if (tokens.access_token) {\n const accessTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.access_token,\n cachedJWKS,\n {\n issuer: getIssuerVariations(issuer),\n },\n );\n accessTokenPayload = accessTokenResponse.payload;\n }\n\n return withoutUndefined({\n id_token: idTokenResponse.payload,\n access_token: accessTokenPayload,\n ...(tokens?.refresh_token ? { refresh_token: tokens.refresh_token } : {}),\n });\n}\n\n/**\n * Get backend endpoints with default values merged with custom configuration\n * @param backendEndpoints - Optional custom backend endpoints configuration\n * @returns Backend endpoints with defaults applied\n */\nexport function getBackendEndpoints(\n backendEndpoints?: BackendEndpoints,\n): BackendEndpoints {\n return {\n refresh: backendEndpoints?.refresh ?? \"/auth/refresh\",\n logout: backendEndpoints?.logout ?? \"/auth/logout\",\n user: backendEndpoints?.user ?? \"/auth/user\",\n };\n}\n\n/**\n * Resolves an endpoint URL by checking if it's already a full URL\n * or if it needs to be combined with a base URL\n * @param baseUrl - The base URL (e.g., \"https://api.example.com\")\n * @param endpoint - The endpoint that might be relative (e.g., \"/auth/logout\") or absolute (e.g., \"https://other-server.com/logout\")\n * @returns The resolved URL\n */\nexport function resolveEndpointUrl(\n baseUrl: string,\n endpoint: string | undefined,\n): string {\n // Handle undefined endpoint\n if (!endpoint) {\n throw new Error(\"Endpoint is undefined\");\n }\n\n // Check if endpoint is already a full URL\n if (endpoint.startsWith(\"http://\") || endpoint.startsWith(\"https://\")) {\n return endpoint;\n }\n\n // Concatenate base URL with relative endpoint\n return `${baseUrl}${endpoint}`;\n}\n\n/**\n * Determines the protocol from request headers or environment\n * Checks common proxy headers before falling back to URL or environment\n */\nexport function getProtocolFromRequest(request?: Request): string {\n if (!request) {\n // Fallback when no request available\n return process.env.NODE_ENV === \"production\" ? \"https:\" : \"http:\";\n }\n\n // Check common proxy headers that indicate the original protocol\n const forwardedProto = request.headers.get(\"x-forwarded-proto\");\n if (forwardedProto) {\n return forwardedProto === \"https\" ? \"https:\" : \"http:\";\n }\n\n const forwardedProtocol = request.headers.get(\"x-forwarded-protocol\");\n if (forwardedProtocol) {\n return forwardedProtocol === \"https\" ? \"https:\" : \"http:\";\n }\n\n // Parse the standard Forwarded header (RFC 7239)\n const forwarded = request.headers.get(\"forwarded\");\n if (forwarded) {\n const protoMatch = forwarded.match(/proto=([^;,\\s]+)/i);\n if (protoMatch) {\n return protoMatch[1] === \"https\" ? \"https:\" : \"http:\";\n }\n }\n\n // Extract from the request URL itself\n const url = new URL(request.url);\n return url.protocol;\n}\n\n/**\n * Detect Safari browser from user agent\n */\nexport function isSafariBrowser(request?: Request): boolean {\n if (!request) return false;\n\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n return userAgent.includes(\"Safari\") && !userAgent.includes(\"Chrome\");\n}\n\n/**\n * Detect if running on localhost\n */\nexport function isLocalhostUrl(request?: Request): boolean {\n if (!request) return false;\n\n const url = new URL(request.url);\n return url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\";\n}\n\n/**\n * Get cookie configuration based on environment and browser\n * Handles special cases for Safari on localhost and HTTPS detection\n *\n * @param request - Optional request object for environment detection\n * @returns Cookie configuration with secure and sameSite settings\n *\n * Configuration rules:\n * - Safari on localhost: Uses lax sameSite to avoid cross-origin issues\n * - HTTPS: Uses secure cookies with none sameSite for cross-origin iframe support\n * - HTTP localhost (non-Safari): Uses secure cookies for Chrome's localhost exception\n */\nexport function getCookieConfiguration(request?: Request): {\n secure: boolean;\n sameSite: \"lax\" | \"none\";\n} {\n const isSafari = isSafariBrowser(request);\n const isLocalhost = isLocalhostUrl(request);\n const protocol = getProtocolFromRequest(request);\n const isHttps = protocol === \"https:\";\n\n if (isSafari && isLocalhost) {\n // Safari on localhost: use lax to avoid cross-origin issues\n return {\n secure: false,\n sameSite: \"lax\",\n };\n } else if (isHttps) {\n // HTTPS (production): use none for cross-origin iframe support\n return {\n secure: true,\n sameSite: \"none\",\n };\n } else {\n // HTTP localhost (non-Safari): use secure: true for iframe compatibility\n // Chrome allows secure cookies on localhost HTTP\n // This allows secure: true cookies to work on localhost for iframe compatibility\n // Reference: Chrome's third-party cookie documentation\n return {\n secure: true,\n sameSite: \"none\",\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/shared/lib/util.ts"],"names":[],"mappings":"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","sourcesContent":["// Utility functions shared by auth server and client integrations\n// Typically these functions should be used inside AuthenticationInitiator and AuthenticationResolver implementations\nimport type {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n ParsedTokens,\n} from \"@/types.js\";\nimport {\n AUTH_SERVER_LEGACY_SESSION,\n AUTH_SERVER_SESSION,\n OAuthTokenTypes,\n} from \"./types.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { addSlashIfNeeded, getOauthEndpoints } from \"@/lib/oauth.js\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport type { PKCEConsumer, PKCEProducer } from \"@/services/types.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { decodeJwt } from \"jose\";\nimport type { CookieStorage } from \"./storage.js\";\nimport {\n AUTOREFRESH_TIMEOUT_NAME,\n LOGOUT_STATE,\n MAX_COOKIE_AGE_SECONDS,\n REFRESH_IN_PROGRESS,\n} from \"@/constants.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport type { AuthConfig, BackendEndpoints } from \"@/server/config.js\";\nimport { verify, type VerifyOptions } from \"@civic/auth-verify\";\n\nconst logger = loggers.services.validation;\n/**\n * Given a PKCE code verifier, derive the code challenge using SHA\n */\nexport async function deriveCodeChallenge(\n codeVerifier: string,\n method: \"Plain\" | \"S256\" = \"S256\",\n): Promise<string> {\n if (method === \"Plain\") {\n console.warn(\"Using insecure plain code challenge method\");\n return codeVerifier;\n }\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport async function getEndpointsWithOverrides(\n oauthServer: string,\n endpointOverrides: Partial<Endpoints> = {},\n): Promise<Endpoints> {\n const endpoints = await getOauthEndpoints(oauthServer);\n return {\n ...endpoints,\n ...endpointOverrides,\n };\n}\n\nexport async function generateOauthLoginUrl(config: {\n clientId: string;\n scopes: string[];\n state: string;\n redirectUrl: string;\n oauthServer: string;\n nonce?: string;\n endpointOverrides?: Partial<Endpoints>;\n // Optional PKCE challenge - not needed for confidential clients using client secrets\n pkceConsumer?: PKCEConsumer;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state: config.state,\n scopes: config.scopes,\n });\n\n // Only add PKCE parameters if a pkceConsumer is provided\n if (config.pkceConsumer) {\n const challenge = await config.pkceConsumer.getCodeChallenge();\n // The OAuth2 client supports PKCE, but does not allow passing in a code challenge from some other source\n // It only allows passing in a code verifier which it then hashes itself.\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n }\n\n if (config.nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", config.nonce);\n }\n // Required by the auth server for offline_access scope\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n\n return oAuthUrl;\n}\n\nexport async function generateOauthLogoutUrl(config: {\n clientId: string;\n redirectUrl: string;\n idToken: string;\n state: string;\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const endSessionUrl = new URL(endpoints.endsession);\n endSessionUrl.searchParams.append(\"client_id\", config.clientId);\n endSessionUrl.searchParams.append(\"id_token_hint\", config.idToken);\n endSessionUrl.searchParams.append(\"state\", config.state);\n endSessionUrl.searchParams.append(\n \"post_logout_redirect_uri\",\n config.redirectUrl,\n );\n return endSessionUrl;\n}\n\nexport function buildOauth2Client(\n clientId: string,\n redirectUri: string,\n endpoints: Endpoints,\n): OAuth2Client {\n return new OAuth2Client(clientId, endpoints.auth, endpoints.token, {\n redirectURI: redirectUri,\n });\n}\n\nexport async function exchangeTokens(\n code: string,\n state: string,\n pkceProducer: PKCEProducer | null,\n oauth2Client: OAuth2Client,\n authConfig: ValidationConfig,\n) {\n // Get code verifier if using PKCE\n const codeVerifier = pkceProducer\n ? await pkceProducer.getCodeVerifier()\n : null;\n\n // Ensure at least one authentication method is provided\n if (!codeVerifier && !authConfig.clientSecret) {\n throw new Error(\n \"Either PKCE code verifier or client secret must be provided\",\n );\n }\n\n // Build options for validateAuthorizationCode\n const validationOptions: Record<string, string> = {};\n\n if (codeVerifier) {\n validationOptions.codeVerifier = codeVerifier;\n }\n\n if (authConfig.clientSecret) {\n validationOptions.credentials = authConfig.clientSecret;\n validationOptions.authenticateWith = \"request_body\"; // Use client_secret_post method\n }\n\n const tokens = (await oauth2Client.validateAuthorizationCode(\n code,\n validationOptions,\n )) as OIDCTokenResponseBody;\n\n // Validate relevant tokens\n try {\n await validateOauth2Tokens(tokens, authConfig);\n } catch (error) {\n console.error(\"tokenExchange error\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n return tokens;\n}\n/**\n * Calculates the maxAge values for access and refresh token cookies\n * based on the TTL values in the access token\n *\n * maxAge needs to be in seconds from now until expiration\n *\n * @param tokens OIDC tokens response containing the access token\n * @returns Object with accessTokenMaxAge and refreshTokenMaxAge in seconds\n */\nexport const getCookiesMaxAge = (\n tokens: OIDCTokenResponseBody,\n): { idTokenMaxAge: number; accessTokenMaxAge: number } => {\n const DEFAULT_TTL = 60 * 60; // 1 hour default\n\n let idTokenMaxAge = DEFAULT_TTL;\n let accessTokenMaxAge = DEFAULT_TTL;\n\n // The ID token takes priority, as it represents the OIDC session\n if (tokens.id_token) {\n // If no access token exists, try to get expiration from ID token\n const parsedIdToken = decodeJwt(tokens.id_token);\n if (parsedIdToken?.exp) {\n const now = Math.floor(Date.now() / 1000);\n idTokenMaxAge = parsedIdToken.exp - now;\n }\n }\n\n if (tokens.access_token) {\n // Get access token TTL from the token if it exists\n const parsedAccessToken = decodeJwt(tokens.access_token);\n accessTokenMaxAge =\n Number(parsedAccessToken?.accessTokenTTL) || DEFAULT_TTL;\n\n // If access token has exp claim, use that directly\n if (parsedAccessToken?.exp) {\n const now = Math.floor(Date.now() / 1000);\n accessTokenMaxAge = parsedAccessToken.exp - now;\n }\n }\n\n return {\n accessTokenMaxAge,\n idTokenMaxAge,\n };\n};\n\nexport async function setOidcSessionExpiresAt(\n storage: AuthStorage | CookieStorage,\n tokens: OIDCTokenResponseBody,\n) {\n const now = Math.floor(Date.now() / 1000);\n const { idTokenMaxAge } = getCookiesMaxAge(tokens);\n // The OIDC session expiry is linked to the ID token expiry, since this is primarily an OIDC client.\n await storage.set(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n (idTokenMaxAge + now).toString(),\n );\n}\n\nexport async function storeTokens(\n storage: AuthStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // ID token is the primary token and must always be stored\n await storage.set(OAuthTokenTypes.ID_TOKEN, tokens.id_token);\n\n // Only store access token if it exists (no longer required)\n if (tokens.access_token) {\n await storage.set(OAuthTokenTypes.ACCESS_TOKEN, tokens.access_token);\n }\n\n // Store refresh token if it exists\n if (tokens.refresh_token) {\n await storage.set(OAuthTokenTypes.REFRESH_TOKEN, tokens.refresh_token);\n }\n\n // Still set access token expiration even if no access token\n // (will get expiration from ID token in this case)\n await setOidcSessionExpiresAt(storage, tokens);\n}\n\n/**\n * Stores tokens in server-side cookies with appropriate expiration times\n * Uses TTL values from the tokens to set cookie maxAge values\n * Refresh token is set with 400 day expiry\n */\nexport async function storeServerTokens(\n storage: AuthStorage | CookieStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // Get maxAge values based on token TTLs (refresh token TTL will be undefined)\n const now = Math.floor(Date.now() / 1000);\n const { idTokenMaxAge, accessTokenMaxAge } = getCookiesMaxAge(tokens);\n\n // The OIDC session expiry is linked to the ID token expiry, since this is primarily an OIDC client.\n const oidcSessionExpiresAt = now + idTokenMaxAge;\n const cookieStorage = storage as CookieStorage;\n\n // Apply maxAge to cookie options\n const accessTokenCookieOptions = {\n maxAge: accessTokenMaxAge,\n };\n\n const refreshTokenCookieOptions = {\n maxAge: MAX_COOKIE_AGE_SECONDS,\n };\n\n // ID token is always stored (primary authentication token)\n await cookieStorage.set(OAuthTokenTypes.ID_TOKEN, tokens.id_token, {\n maxAge: idTokenMaxAge,\n });\n\n // Access token is optional - only set if it exists\n if (tokens.access_token) {\n await cookieStorage.set(\n OAuthTokenTypes.ACCESS_TOKEN,\n tokens.access_token,\n accessTokenCookieOptions,\n );\n }\n\n // Set refresh token if present with 400 day expiry\n if (tokens.refresh_token) {\n await cookieStorage.set(\n OAuthTokenTypes.REFRESH_TOKEN,\n tokens.refresh_token,\n refreshTokenCookieOptions,\n );\n }\n\n // Still store the access token expiration timestamp even if no access token\n await storage.set(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n oidcSessionExpiresAt.toString(),\n {\n // This is primarily an OIDC client, so we use the ID token max age for the session timeout / refresh scheduling.\n maxAge: idTokenMaxAge,\n },\n );\n logger.debug(\"storeServerTokens\", {\n oidcSessionExpiresAt,\n refreshTokenMaxAge: MAX_COOKIE_AGE_SECONDS,\n idTokenMaxAge,\n hasAccessToken: !!tokens.access_token,\n });\n}\n\nexport async function clearTokens(storage: AuthStorage | CookieStorage) {\n // clear all local storage keys related to OAuth and CivicAuth SDK\n const clearOAuthPromises = [\n ...Object.values(OAuthTokenTypes),\n REFRESH_IN_PROGRESS,\n AUTOREFRESH_TIMEOUT_NAME,\n LOGOUT_STATE,\n ].map(async (key) => {\n await storage.delete(key);\n });\n await Promise.all([...clearOAuthPromises]);\n}\n\nexport async function clearAuthServerSession(storage: AuthStorage) {\n await storage.delete(AUTH_SERVER_SESSION);\n await storage.delete(AUTH_SERVER_LEGACY_SESSION);\n}\n\nexport async function clearUser(storage: AuthStorage) {\n const userSession = new GenericUserSession(storage);\n await userSession.clear();\n}\n\n/**\n * Smart token unwrapping for Safari's base64-encoding bug\n * Only unwraps tokens that are:\n * 1. Base64-encoded (Safari bug) - very long strings without dots\n * 2. Contain a JSON object with a 'value' property that's a valid JWT\n *\n * Does NOT unwrap React Router's normal {value: \"token\"} objects\n */\nfunction unwrapSafariTokenIfNeeded(token: string | null): string | null {\n if (!token) return token;\n\n // Safari-specific detection: base64-encoded JSON that's extremely long\n // Normal wrapped objects from React Router are much shorter and have different characteristics\n if (token && !token.includes(\".\") && token.length > 800) {\n try {\n // Try to decode as base64 and parse as JSON\n const decoded = JSON.parse(atob(token));\n\n // Verify this is Safari's bug: wrapped value must be a valid 3-part JWT\n if (\n decoded &&\n typeof decoded === \"object\" &&\n decoded.value &&\n typeof decoded.value === \"string\" &&\n decoded.value.split(\".\").length === 3\n ) {\n return decoded.value;\n }\n } catch (error) {\n console.error(\"HERE UTIL - SAFARI TOKEN UNWRAP FAILED\", error);\n }\n }\n\n return token;\n}\n\nexport async function retrieveTokens(\n storage: AuthStorage,\n): Promise<Partial<OIDCTokenResponseBody> | null> {\n const idToken = await storage.get(OAuthTokenTypes.ID_TOKEN);\n const accessToken = await storage.get(OAuthTokenTypes.ACCESS_TOKEN);\n const refreshToken = await storage.get(OAuthTokenTypes.REFRESH_TOKEN);\n const oidcSessionExpiresAt = await storage.get(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n );\n\n return {\n id_token: unwrapSafariTokenIfNeeded(idToken) ?? undefined,\n access_token: unwrapSafariTokenIfNeeded(accessToken) ?? undefined,\n refresh_token: unwrapSafariTokenIfNeeded(refreshToken) ?? undefined,\n oidc_session_expires_at:\n oidcSessionExpiresAt !== null\n ? parseInt(oidcSessionExpiresAt, 10)\n : undefined, // Convert string to number\n };\n}\n\nexport async function retrieveOidcSessionExpiredAtSeconds(\n storage: AuthStorage,\n): Promise<number | null> {\n const valueSeconds = await storage.get(\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n );\n if (!valueSeconds) {\n return null;\n }\n const expiresAt = Number(valueSeconds);\n return isNaN(expiresAt) ? null : expiresAt;\n}\n\nexport type ValidationConfig = Pick<\n AuthConfig,\n \"clientId\" | \"oauthServer\" | \"oauthServerBaseUrl\" | \"clientSecret\"\n>;\nexport async function validateOauth2Tokens(\n tokens: OIDCTokenResponseBody,\n config: ValidationConfig,\n): Promise<ParsedTokens> {\n const baseIssuer = addSlashIfNeeded(\n (config.oauthServer || config.oauthServerBaseUrl) ??\n \"https://auth.civic.com/oauth/\",\n );\n\n // Validate the ID token - this is now the primary token for authentication\n const idTokenVerifyOptions: VerifyOptions = {\n issuer: baseIssuer,\n };\n\n // Set audience for ID token\n if (config.clientId) {\n // ID tokens should have the client ID as audience for proper OIDC compliance\n idTokenVerifyOptions.aud = config.clientId;\n }\n\n logger.debug(`Verifying id_token with options:`, {\n idTokenVerifyOptions,\n config,\n });\n\n // Use the @civic/auth-verify package for ID token verification\n const idTokenPayload = await verify(tokens.id_token, idTokenVerifyOptions);\n\n // Only validate the access token if it exists, but if present it must be valid\n let accessTokenPayload;\n if (tokens.access_token) {\n const accessTokenVerifyOptions: VerifyOptions = {\n issuer: baseIssuer,\n // Access tokens have \"civic\" as audience based on auth server configuration\n aud: \"civic\",\n clientId: config.clientId,\n };\n\n logger.debug(`Verifying access_token with options:`, {\n accessTokenVerifyOptions,\n });\n\n // Use the @civic/auth-verify package for access token verification\n accessTokenPayload = await verify(\n tokens.access_token,\n accessTokenVerifyOptions,\n );\n }\n\n return withoutUndefined({\n id_token: idTokenPayload,\n access_token: accessTokenPayload,\n ...(tokens?.refresh_token ? { refresh_token: tokens.refresh_token } : {}),\n });\n}\n\n/**\n * Get backend endpoints with default values merged with custom configuration\n * @param backendEndpoints - Optional custom backend endpoints configuration\n * @returns Backend endpoints with defaults applied\n */\nexport function getBackendEndpoints(\n backendEndpoints?: BackendEndpoints,\n): BackendEndpoints {\n return {\n refresh: backendEndpoints?.refresh ?? \"/auth/refresh\",\n logout: backendEndpoints?.logout ?? \"/auth/logout\",\n user: backendEndpoints?.user ?? \"/auth/user\",\n };\n}\n\n/**\n * Resolves an endpoint URL by checking if it's already a full URL\n * or if it needs to be combined with a base URL\n * @param baseUrl - The base URL (e.g., \"https://api.example.com\")\n * @param endpoint - The endpoint that might be relative (e.g., \"/auth/logout\") or absolute (e.g., \"https://other-server.com/logout\")\n * @returns The resolved URL\n */\nexport function resolveEndpointUrl(\n baseUrl: string,\n endpoint: string | undefined,\n): string {\n // Handle undefined endpoint\n if (!endpoint) {\n throw new Error(\"Endpoint is undefined\");\n }\n\n // Check if endpoint is already a full URL\n if (endpoint.startsWith(\"http://\") || endpoint.startsWith(\"https://\")) {\n return endpoint;\n }\n\n // Concatenate base URL with relative endpoint\n return `${baseUrl}${endpoint}`;\n}\n\n/**\n * Determines the protocol from request headers or environment\n * Checks common proxy headers before falling back to URL or environment\n */\nexport function getProtocolFromRequest(request?: Request): string {\n if (!request) {\n // Fallback when no request available\n return process.env.NODE_ENV === \"production\" ? \"https:\" : \"http:\";\n }\n\n // Check common proxy headers that indicate the original protocol\n const forwardedProto = request.headers.get(\"x-forwarded-proto\");\n if (forwardedProto) {\n return forwardedProto === \"https\" ? \"https:\" : \"http:\";\n }\n\n const forwardedProtocol = request.headers.get(\"x-forwarded-protocol\");\n if (forwardedProtocol) {\n return forwardedProtocol === \"https\" ? \"https:\" : \"http:\";\n }\n\n // Parse the standard Forwarded header (RFC 7239)\n const forwarded = request.headers.get(\"forwarded\");\n if (forwarded) {\n const protoMatch = forwarded.match(/proto=([^;,\\s]+)/i);\n if (protoMatch) {\n return protoMatch[1] === \"https\" ? \"https:\" : \"http:\";\n }\n }\n\n // Extract from the request URL itself\n const url = new URL(request.url);\n return url.protocol;\n}\n\n/**\n * Detect Safari browser from user agent\n */\nexport function isSafariBrowser(request?: Request): boolean {\n if (!request) return false;\n\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n return userAgent.includes(\"Safari\") && !userAgent.includes(\"Chrome\");\n}\n\n/**\n * Detect if running on localhost\n */\nexport function isLocalhostUrl(request?: Request): boolean {\n if (!request) return false;\n\n const url = new URL(request.url);\n return url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\";\n}\n\n/**\n * Get cookie configuration based on environment and browser\n * Handles special cases for Safari on localhost and HTTPS detection\n *\n * @param request - Optional request object for environment detection\n * @returns Cookie configuration with secure and sameSite settings\n *\n * Configuration rules:\n * - Safari on localhost: Uses lax sameSite to avoid cross-origin issues\n * - HTTPS: Uses secure cookies with none sameSite for cross-origin iframe support\n * - HTTP localhost (non-Safari): Uses secure cookies for Chrome's localhost exception\n */\nexport function getCookieConfiguration(request?: Request): {\n secure: boolean;\n sameSite: \"lax\" | \"none\";\n} {\n const isSafari = isSafariBrowser(request);\n const isLocalhost = isLocalhostUrl(request);\n const protocol = getProtocolFromRequest(request);\n const isHttps = protocol === \"https:\";\n\n if (isSafari && isLocalhost) {\n // Safari on localhost: use lax to avoid cross-origin issues\n return {\n secure: false,\n sameSite: \"lax\",\n };\n } else if (isHttps) {\n // HTTPS (production): use none for cross-origin iframe support\n return {\n secure: true,\n sameSite: \"none\",\n };\n } else {\n // HTTP localhost (non-Safari): use secure: true for iframe compatibility\n // Chrome allows secure cookies on localhost HTTP\n // This allows secure: true cookies to work on localhost for iframe compatibility\n // Reference: Chrome's third-party cookie documentation\n return {\n secure: true,\n sameSite: \"none\",\n };\n }\n}\n"]}
|
package/dist/shared/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "@civic/auth:0.11.
|
|
1
|
+
export declare const VERSION = "@civic/auth:0.11.2";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/shared/version.js
CHANGED
|
@@ -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.11.
|
|
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.11.2\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OAuthCallbackHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/OAuthCallbackHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAWH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAI5E;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,qBAAqB,EAC7B,cAAc,EAAE,WAAW,EAC3B,cAAc;;;;;CAAiC,GAC9C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBxB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"OAuthCallbackHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/OAuthCallbackHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAWH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAI5E;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,qBAAqB,EAC7B,cAAc,EAAE,WAAW,EAC3B,cAAc;;;;;CAAiC,GAC9C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBxB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,OAAO,CAAC,CAgQlB"}
|
|
@@ -166,7 +166,7 @@ export async function handleOAuthRedirectPage(config) {
|
|
|
166
166
|
try {
|
|
167
167
|
const endpoints = await getEndpointsWithOverrides(config.oauthServer);
|
|
168
168
|
const oauth2Client = buildOauth2Client(config.clientId, config.redirectUrl, endpoints);
|
|
169
|
-
const tokenResponse = await exchangeTokens(code, state, pkceProducer, oauth2Client, config.
|
|
169
|
+
const tokenResponse = await exchangeTokens(code, state, pkceProducer, oauth2Client, { clientId: config.clientId, oauthServer: config.oauthServer });
|
|
170
170
|
// Get userInfo from storeTokens using shared utilities
|
|
171
171
|
const userInfo = await storeTokens(tokenResponse, storage, loggerInstance);
|
|
172
172
|
loggerInstance.info("CivicAuth: Tokens stored successfully using shared utilities.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OAuthCallbackHandler.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/OAuthCallbackHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OAuth Callback Handler for Vanilla JavaScript Applications\n *\n * This module provides functionality for handling OAuth redirect/callback pages in vanilla JavaScript\n * applications using the Civic Auth system. It processes the OAuth authorization code flow completion\n * by exchanging authorization codes for access tokens and managing the authentication state.\n *\n * Key responsibilities:\n * - Process OAuth callback URL parameters (code, state)\n * - Exchange authorization codes for access tokens using PKCE\n * - Store tokens and user session data using shared utilities\n * - Create DOM signals for iframe-based authentication flows\n * - Handle error states and cleanup during the OAuth flow\n *\n * This module works in conjunction with:\n * - CivicAuth class for initiating OAuth flows\n * - SignalObserver for detecting authentication completion in iframes\n * - Shared token storage utilities for consistent state management\n *\n * @example\n * ```javascript\n * // Basic usage\n * const config = {\n * clientId: 'your-client-id',\n * redirectUrl: 'https://yourapp.com/callback',\n * oauthServer: 'https://auth.civic.com/oauth',\n * scopes: ['openid', 'profile', 'email']\n * };\n * const result = await handleOAuthRedirectPage(config);\n * ```\n */\n\nimport {\n exchangeTokens,\n buildOauth2Client,\n getEndpointsWithOverrides,\n storeTokens as sharedStoreTokens,\n} from \"../../../shared/lib/util.js\";\nimport { getUser } from \"../../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../../shared/lib/UserSession.js\";\nimport { CodeVerifier } from \"../../../shared/lib/types.js\";\nimport type { getCurrentLogger } from \"../../utils/logger.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nimport { GenericPublicClientPKCEProducer } from \"../../../services/PKCE.js\";\nimport type { AuthStorage, OIDCTokenResponseBody } from \"../../../types.js\";\nimport { removeParamsWithoutReload } from \"../../../lib/windowUtil.js\";\nimport { DEFAULT_OAUTH_GET_PARAMS } from \"../../../constants.js\";\n\n/**\n * Store tokens using the shared utilities from /shared/lib\n * This ensures consistency with the React implementation and also handles user session storage\n */\nexport async function storeTokens(\n tokens: OIDCTokenResponseBody,\n storageAdapter: AuthStorage,\n loggerInstance = createLogger(\"oauth-callback\"),\n): Promise<object | null> {\n try {\n // Use shared storeTokens utility for consistent token storage\n await sharedStoreTokens(storageAdapter, tokens);\n\n // Get user info using shared utilities\n const user = await getUser(storageAdapter);\n if (user) {\n // Store user session using shared utilities\n const userSession = new GenericUserSession(storageAdapter);\n await userSession.set(user);\n loggerInstance.info(\n \"CivicAuth: Tokens and user info stored successfully using shared utilities.\",\n );\n return user;\n } else {\n loggerInstance.warn(\n \"CivicAuth: Failed to extract user info from tokens.\",\n );\n return null;\n }\n } catch (error) {\n loggerInstance.error(\"CivicAuth: Error storing tokens:\", error);\n throw error;\n }\n}\n\nexport interface HandleOAuthRedirectConfig {\n clientId: string;\n redirectUrl: string;\n oauthServer: string;\n textSignals: {\n success: string;\n error: string;\n };\n storageAdapter: AuthStorage;\n logger?: ReturnType<typeof getCurrentLogger>;\n}\n\n/**\n * Handle OAuth redirect page processing for vanilla JavaScript applications.\n * This function processes the OAuth callback URL parameters and exchanges the authorization code for tokens.\n *\n * @param config - Configuration object for handling the OAuth redirect\n * @param config.clientId - OAuth client ID\n * @param config.redirectUrl - URL to redirect to after authentication\n * @param config.oauthServer - OAuth server base URL\n * @param config.textSignals - Text signals for success and error states\n * @param config.storageAdapter - Storage adapter for persisting auth state (required)\n * @param config.logger - Optional logger instance\n * @returns Promise<boolean> - Returns true if callback was handled, false otherwise\n *\n * @example\n * ```javascript\n * // Using storeTokens with default iframe mode\n * const config = {\n * clientId: 'your-client-id',\n * redirectUrl: 'https://yourapp.com/callback',\n * oauthServer: 'https://auth.civic.com/oauth',\n * scopes: ['openid', 'profile', 'email']\n * };\n * await storeTokens(params, config);\n * ```\n */\nexport async function handleOAuthRedirectPage(\n config: HandleOAuthRedirectConfig,\n): Promise<boolean> {\n const loggerInstance = config.logger || createLogger(\"oauth-callback\");\n const urlParams = new URLSearchParams(window.location.search);\n const code = urlParams.get(\"code\");\n const state = urlParams.get(\"state\");\n const error = urlParams.get(\"error\");\n\n // Check if we're in a popup window\n const isPopup = window.opener && window.opener !== window;\n loggerInstance.info(\"CivicAuth: Callback page context\", {\n isPopup,\n hasOpener: !!window.opener,\n hasCode: !!code,\n hasError: !!error,\n currentUrl: window.location.href,\n });\n\n if (error) {\n loggerInstance.error(\"CivicAuth: OAuth error in callback\", { error });\n\n // Create error signal for iframe mode\n const errorSignalElement = document.createElement(\"div\");\n errorSignalElement.id = \"civic-auth-error-signal\";\n errorSignalElement.textContent = `${config.textSignals.error} (Error: ${error})`;\n errorSignalElement.style.display = \"none\";\n document.body.appendChild(errorSignalElement);\n\n // Send postMessage for popup mode\n if (isPopup && window.opener) {\n loggerInstance.info(\"CivicAuth: Sending error message to parent window\", {\n hasOpener: !!window.opener,\n openerOrigin: window.opener.origin || \"unknown\",\n currentUrl: window.location.href,\n messageData: {\n type: \"auth_error\",\n detail: `OAuth error: ${error}`,\n error: error,\n },\n });\n\n try {\n window.opener.postMessage(\n {\n type: \"auth_error\",\n detail: `OAuth error: ${error}`,\n error: error,\n },\n \"*\",\n );\n loggerInstance.info(\"CivicAuth: Error postMessage sent successfully\");\n } catch (postMessageError) {\n loggerInstance.error(\"CivicAuth: Failed to send error postMessage\", {\n error: postMessageError,\n });\n }\n\n // Close popup after a short delay\n setTimeout(() => {\n loggerInstance.info(\"CivicAuth: Closing popup window\");\n try {\n window.close();\n } catch (closeError) {\n loggerInstance.warn(\"CivicAuth: Failed to close popup window\", {\n error: closeError,\n });\n }\n }, 1000);\n } else {\n loggerInstance.debug(\"CivicAuth: Not in popup mode or no opener\", {\n isPopup,\n hasOpener: !!window.opener,\n });\n }\n\n return true;\n }\n\n if (code && state) {\n loggerInstance.info(\"CivicAuth: OAuth callback detected with code:\", code);\n\n // Use the provided storage adapter from config\n const storage = config.storageAdapter;\n const pkceProducer = new GenericPublicClientPKCEProducer(storage);\n\n try {\n const endpoints = await getEndpointsWithOverrides(config.oauthServer);\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n\n const tokenResponse = await exchangeTokens(\n code,\n state,\n pkceProducer,\n oauth2Client,\n config.oauthServer,\n endpoints,\n );\n\n // Get userInfo from storeTokens using shared utilities\n const userInfo = await storeTokens(\n tokenResponse,\n storage,\n loggerInstance,\n );\n loggerInstance.info(\n \"CivicAuth: Tokens stored successfully using shared utilities.\",\n );\n\n // Create success signal for iframe mode\n const signalElement = document.createElement(\"div\");\n signalElement.id = \"civic-auth-success-signal\";\n signalElement.textContent = config.textSignals.success;\n if (userInfo) {\n // Embed userInfo if available\n signalElement.setAttribute(\"data-user-info\", JSON.stringify(userInfo));\n }\n signalElement.style.display = \"none\";\n document.body.appendChild(signalElement);\n loggerInstance.info(\"CivicAuth: Appended success signal to body.\");\n\n // Clean up OAuth parameters from URL for redirect mode\n if (!isPopup) {\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n loggerInstance.info(\"CivicAuth: Cleaned up OAuth parameters from URL.\");\n }\n\n // Send postMessage for popup mode\n if (isPopup && window.opener) {\n loggerInstance.info(\n \"CivicAuth: Sending success message to parent window\",\n {\n hasOpener: !!window.opener,\n openerOrigin: window.opener.origin || \"unknown\",\n currentUrl: window.location.href,\n messageData: {\n type: \"auth_success\",\n detail: \"Authentication successful\",\n hasUser: !!userInfo,\n hasTokens: !!tokenResponse,\n },\n },\n );\n\n try {\n window.opener.postMessage(\n {\n type: \"auth_success\",\n detail: \"Authentication successful\",\n data: {\n user: userInfo,\n tokens: tokenResponse,\n },\n },\n \"*\",\n );\n loggerInstance.info(\n \"CivicAuth: Success postMessage sent successfully\",\n );\n } catch (postMessageError) {\n loggerInstance.error(\n \"CivicAuth: Failed to send success postMessage\",\n {\n error: postMessageError,\n },\n );\n }\n\n // Close popup after a short delay\n setTimeout(() => {\n loggerInstance.info(\"CivicAuth: Closing popup window\");\n try {\n window.close();\n } catch (closeError) {\n loggerInstance.warn(\"CivicAuth: Failed to close popup window\", {\n error: closeError,\n });\n }\n }, 1000);\n } else {\n loggerInstance.debug(\"CivicAuth: Not in popup mode or no opener\", {\n isPopup,\n hasOpener: !!window.opener,\n });\n }\n\n // Clean up the code verifier using shared utilities\n await storage.delete(CodeVerifier.COOKIE_NAME);\n } catch (error) {\n loggerInstance.error(\"CivicAuth: Token exchange error:\", error);\n\n // Create error signal for iframe mode\n const errorSignalElement = document.createElement(\"div\");\n errorSignalElement.id = \"civic-auth-error-signal\";\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n errorSignalElement.textContent = `${config.textSignals.error} (Error: ${errorMessage})`;\n errorSignalElement.style.display = \"none\";\n document.body.appendChild(errorSignalElement);\n\n // Send postMessage for popup mode\n if (isPopup && window.opener) {\n loggerInstance.info(\n \"CivicAuth: Sending error message to parent window\",\n {\n hasOpener: !!window.opener,\n openerOrigin: window.opener.origin || \"unknown\",\n currentUrl: window.location.href,\n messageData: {\n type: \"auth_error\",\n detail: `Token exchange error: ${errorMessage}`,\n error: errorMessage,\n },\n },\n );\n\n try {\n window.opener.postMessage(\n {\n type: \"auth_error\",\n detail: `Token exchange error: ${errorMessage}`,\n error: errorMessage,\n },\n \"*\",\n );\n loggerInstance.info(\"CivicAuth: Error postMessage sent successfully\");\n } catch (postMessageError) {\n loggerInstance.error(\"CivicAuth: Failed to send error postMessage\", {\n error: postMessageError,\n });\n }\n\n // Close popup after a short delay\n setTimeout(() => {\n loggerInstance.info(\"CivicAuth: Closing popup window\");\n try {\n window.close();\n } catch (closeError) {\n loggerInstance.warn(\"CivicAuth: Failed to close popup window\", {\n error: closeError,\n });\n }\n }, 1000);\n } else {\n loggerInstance.debug(\"CivicAuth: Not in popup mode or no opener\", {\n isPopup,\n hasOpener: !!window.opener,\n });\n }\n\n return true;\n }\n return true;\n }\n return false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OAuthCallbackHandler.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/OAuthCallbackHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OAuth Callback Handler for Vanilla JavaScript Applications\n *\n * This module provides functionality for handling OAuth redirect/callback pages in vanilla JavaScript\n * applications using the Civic Auth system. It processes the OAuth authorization code flow completion\n * by exchanging authorization codes for access tokens and managing the authentication state.\n *\n * Key responsibilities:\n * - Process OAuth callback URL parameters (code, state)\n * - Exchange authorization codes for access tokens using PKCE\n * - Store tokens and user session data using shared utilities\n * - Create DOM signals for iframe-based authentication flows\n * - Handle error states and cleanup during the OAuth flow\n *\n * This module works in conjunction with:\n * - CivicAuth class for initiating OAuth flows\n * - SignalObserver for detecting authentication completion in iframes\n * - Shared token storage utilities for consistent state management\n *\n * @example\n * ```javascript\n * // Basic usage\n * const config = {\n * clientId: 'your-client-id',\n * redirectUrl: 'https://yourapp.com/callback',\n * oauthServer: 'https://auth.civic.com/oauth',\n * scopes: ['openid', 'profile', 'email']\n * };\n * const result = await handleOAuthRedirectPage(config);\n * ```\n */\n\nimport {\n exchangeTokens,\n buildOauth2Client,\n getEndpointsWithOverrides,\n storeTokens as sharedStoreTokens,\n} from \"../../../shared/lib/util.js\";\nimport { getUser } from \"../../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../../shared/lib/UserSession.js\";\nimport { CodeVerifier } from \"../../../shared/lib/types.js\";\nimport type { getCurrentLogger } from \"../../utils/logger.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nimport { GenericPublicClientPKCEProducer } from \"../../../services/PKCE.js\";\nimport type { AuthStorage, OIDCTokenResponseBody } from \"../../../types.js\";\nimport { removeParamsWithoutReload } from \"../../../lib/windowUtil.js\";\nimport { DEFAULT_OAUTH_GET_PARAMS } from \"../../../constants.js\";\n\n/**\n * Store tokens using the shared utilities from /shared/lib\n * This ensures consistency with the React implementation and also handles user session storage\n */\nexport async function storeTokens(\n tokens: OIDCTokenResponseBody,\n storageAdapter: AuthStorage,\n loggerInstance = createLogger(\"oauth-callback\"),\n): Promise<object | null> {\n try {\n // Use shared storeTokens utility for consistent token storage\n await sharedStoreTokens(storageAdapter, tokens);\n\n // Get user info using shared utilities\n const user = await getUser(storageAdapter);\n if (user) {\n // Store user session using shared utilities\n const userSession = new GenericUserSession(storageAdapter);\n await userSession.set(user);\n loggerInstance.info(\n \"CivicAuth: Tokens and user info stored successfully using shared utilities.\",\n );\n return user;\n } else {\n loggerInstance.warn(\n \"CivicAuth: Failed to extract user info from tokens.\",\n );\n return null;\n }\n } catch (error) {\n loggerInstance.error(\"CivicAuth: Error storing tokens:\", error);\n throw error;\n }\n}\n\nexport interface HandleOAuthRedirectConfig {\n clientId: string;\n redirectUrl: string;\n oauthServer: string;\n textSignals: {\n success: string;\n error: string;\n };\n storageAdapter: AuthStorage;\n logger?: ReturnType<typeof getCurrentLogger>;\n}\n\n/**\n * Handle OAuth redirect page processing for vanilla JavaScript applications.\n * This function processes the OAuth callback URL parameters and exchanges the authorization code for tokens.\n *\n * @param config - Configuration object for handling the OAuth redirect\n * @param config.clientId - OAuth client ID\n * @param config.redirectUrl - URL to redirect to after authentication\n * @param config.oauthServer - OAuth server base URL\n * @param config.textSignals - Text signals for success and error states\n * @param config.storageAdapter - Storage adapter for persisting auth state (required)\n * @param config.logger - Optional logger instance\n * @returns Promise<boolean> - Returns true if callback was handled, false otherwise\n *\n * @example\n * ```javascript\n * // Using storeTokens with default iframe mode\n * const config = {\n * clientId: 'your-client-id',\n * redirectUrl: 'https://yourapp.com/callback',\n * oauthServer: 'https://auth.civic.com/oauth',\n * scopes: ['openid', 'profile', 'email']\n * };\n * await storeTokens(params, config);\n * ```\n */\nexport async function handleOAuthRedirectPage(\n config: HandleOAuthRedirectConfig,\n): Promise<boolean> {\n const loggerInstance = config.logger || createLogger(\"oauth-callback\");\n const urlParams = new URLSearchParams(window.location.search);\n const code = urlParams.get(\"code\");\n const state = urlParams.get(\"state\");\n const error = urlParams.get(\"error\");\n\n // Check if we're in a popup window\n const isPopup = window.opener && window.opener !== window;\n loggerInstance.info(\"CivicAuth: Callback page context\", {\n isPopup,\n hasOpener: !!window.opener,\n hasCode: !!code,\n hasError: !!error,\n currentUrl: window.location.href,\n });\n\n if (error) {\n loggerInstance.error(\"CivicAuth: OAuth error in callback\", { error });\n\n // Create error signal for iframe mode\n const errorSignalElement = document.createElement(\"div\");\n errorSignalElement.id = \"civic-auth-error-signal\";\n errorSignalElement.textContent = `${config.textSignals.error} (Error: ${error})`;\n errorSignalElement.style.display = \"none\";\n document.body.appendChild(errorSignalElement);\n\n // Send postMessage for popup mode\n if (isPopup && window.opener) {\n loggerInstance.info(\"CivicAuth: Sending error message to parent window\", {\n hasOpener: !!window.opener,\n openerOrigin: window.opener.origin || \"unknown\",\n currentUrl: window.location.href,\n messageData: {\n type: \"auth_error\",\n detail: `OAuth error: ${error}`,\n error: error,\n },\n });\n\n try {\n window.opener.postMessage(\n {\n type: \"auth_error\",\n detail: `OAuth error: ${error}`,\n error: error,\n },\n \"*\",\n );\n loggerInstance.info(\"CivicAuth: Error postMessage sent successfully\");\n } catch (postMessageError) {\n loggerInstance.error(\"CivicAuth: Failed to send error postMessage\", {\n error: postMessageError,\n });\n }\n\n // Close popup after a short delay\n setTimeout(() => {\n loggerInstance.info(\"CivicAuth: Closing popup window\");\n try {\n window.close();\n } catch (closeError) {\n loggerInstance.warn(\"CivicAuth: Failed to close popup window\", {\n error: closeError,\n });\n }\n }, 1000);\n } else {\n loggerInstance.debug(\"CivicAuth: Not in popup mode or no opener\", {\n isPopup,\n hasOpener: !!window.opener,\n });\n }\n\n return true;\n }\n\n if (code && state) {\n loggerInstance.info(\"CivicAuth: OAuth callback detected with code:\", code);\n\n // Use the provided storage adapter from config\n const storage = config.storageAdapter;\n const pkceProducer = new GenericPublicClientPKCEProducer(storage);\n\n try {\n const endpoints = await getEndpointsWithOverrides(config.oauthServer);\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n\n const tokenResponse = await exchangeTokens(\n code,\n state,\n pkceProducer,\n oauth2Client,\n { clientId: config.clientId, oauthServer: config.oauthServer },\n );\n\n // Get userInfo from storeTokens using shared utilities\n const userInfo = await storeTokens(\n tokenResponse,\n storage,\n loggerInstance,\n );\n loggerInstance.info(\n \"CivicAuth: Tokens stored successfully using shared utilities.\",\n );\n\n // Create success signal for iframe mode\n const signalElement = document.createElement(\"div\");\n signalElement.id = \"civic-auth-success-signal\";\n signalElement.textContent = config.textSignals.success;\n if (userInfo) {\n // Embed userInfo if available\n signalElement.setAttribute(\"data-user-info\", JSON.stringify(userInfo));\n }\n signalElement.style.display = \"none\";\n document.body.appendChild(signalElement);\n loggerInstance.info(\"CivicAuth: Appended success signal to body.\");\n\n // Clean up OAuth parameters from URL for redirect mode\n if (!isPopup) {\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n loggerInstance.info(\"CivicAuth: Cleaned up OAuth parameters from URL.\");\n }\n\n // Send postMessage for popup mode\n if (isPopup && window.opener) {\n loggerInstance.info(\n \"CivicAuth: Sending success message to parent window\",\n {\n hasOpener: !!window.opener,\n openerOrigin: window.opener.origin || \"unknown\",\n currentUrl: window.location.href,\n messageData: {\n type: \"auth_success\",\n detail: \"Authentication successful\",\n hasUser: !!userInfo,\n hasTokens: !!tokenResponse,\n },\n },\n );\n\n try {\n window.opener.postMessage(\n {\n type: \"auth_success\",\n detail: \"Authentication successful\",\n data: {\n user: userInfo,\n tokens: tokenResponse,\n },\n },\n \"*\",\n );\n loggerInstance.info(\n \"CivicAuth: Success postMessage sent successfully\",\n );\n } catch (postMessageError) {\n loggerInstance.error(\n \"CivicAuth: Failed to send success postMessage\",\n {\n error: postMessageError,\n },\n );\n }\n\n // Close popup after a short delay\n setTimeout(() => {\n loggerInstance.info(\"CivicAuth: Closing popup window\");\n try {\n window.close();\n } catch (closeError) {\n loggerInstance.warn(\"CivicAuth: Failed to close popup window\", {\n error: closeError,\n });\n }\n }, 1000);\n } else {\n loggerInstance.debug(\"CivicAuth: Not in popup mode or no opener\", {\n isPopup,\n hasOpener: !!window.opener,\n });\n }\n\n // Clean up the code verifier using shared utilities\n await storage.delete(CodeVerifier.COOKIE_NAME);\n } catch (error) {\n loggerInstance.error(\"CivicAuth: Token exchange error:\", error);\n\n // Create error signal for iframe mode\n const errorSignalElement = document.createElement(\"div\");\n errorSignalElement.id = \"civic-auth-error-signal\";\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n errorSignalElement.textContent = `${config.textSignals.error} (Error: ${errorMessage})`;\n errorSignalElement.style.display = \"none\";\n document.body.appendChild(errorSignalElement);\n\n // Send postMessage for popup mode\n if (isPopup && window.opener) {\n loggerInstance.info(\n \"CivicAuth: Sending error message to parent window\",\n {\n hasOpener: !!window.opener,\n openerOrigin: window.opener.origin || \"unknown\",\n currentUrl: window.location.href,\n messageData: {\n type: \"auth_error\",\n detail: `Token exchange error: ${errorMessage}`,\n error: errorMessage,\n },\n },\n );\n\n try {\n window.opener.postMessage(\n {\n type: \"auth_error\",\n detail: `Token exchange error: ${errorMessage}`,\n error: errorMessage,\n },\n \"*\",\n );\n loggerInstance.info(\"CivicAuth: Error postMessage sent successfully\");\n } catch (postMessageError) {\n loggerInstance.error(\"CivicAuth: Failed to send error postMessage\", {\n error: postMessageError,\n });\n }\n\n // Close popup after a short delay\n setTimeout(() => {\n loggerInstance.info(\"CivicAuth: Closing popup window\");\n try {\n window.close();\n } catch (closeError) {\n loggerInstance.warn(\"CivicAuth: Failed to close popup window\", {\n error: closeError,\n });\n }\n }, 1000);\n } else {\n loggerInstance.debug(\"CivicAuth: Not in popup mode or no opener\", {\n isPopup,\n hasOpener: !!window.opener,\n });\n }\n\n return true;\n }\n return true;\n }\n return false;\n}\n"]}
|