@civic/auth 0.2.2-beta.6 → 0.2.2-beta.7
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 +1 -0
- package/dist/cjs/lib/postMessage.d.ts.map +1 -1
- package/dist/cjs/lib/postMessage.js +0 -1
- package/dist/cjs/lib/postMessage.js.map +1 -1
- package/dist/cjs/nextjs/middleware.d.ts.map +1 -1
- package/dist/cjs/nextjs/middleware.js +0 -5
- package/dist/cjs/nextjs/middleware.js.map +1 -1
- package/dist/cjs/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/cjs/nextjs/routeHandler.js +7 -16
- package/dist/cjs/nextjs/routeHandler.js.map +1 -1
- package/dist/cjs/services/AuthenticationService.d.ts.map +1 -1
- package/dist/cjs/services/AuthenticationService.js +0 -2
- package/dist/cjs/services/AuthenticationService.js.map +1 -1
- package/dist/cjs/shared/components/CivicAuthIframeContainer.js +2 -2
- package/dist/cjs/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/cjs/shared/hooks/useSignIn.js +2 -2
- package/dist/cjs/shared/hooks/useSignIn.js.map +1 -1
- package/dist/cjs/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
- package/dist/cjs/shared/lib/GenericAuthenticationRefresher.js +0 -1
- package/dist/cjs/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
- package/dist/cjs/shared/lib/util.d.ts.map +1 -1
- package/dist/cjs/shared/lib/util.js +0 -1
- package/dist/cjs/shared/lib/util.js.map +1 -1
- package/dist/cjs/shared/version.d.ts +1 -1
- package/dist/cjs/shared/version.js +1 -1
- package/dist/cjs/shared/version.js.map +1 -1
- package/dist/esm/lib/postMessage.d.ts.map +1 -1
- package/dist/esm/lib/postMessage.js +0 -1
- package/dist/esm/lib/postMessage.js.map +1 -1
- package/dist/esm/nextjs/middleware.d.ts.map +1 -1
- package/dist/esm/nextjs/middleware.js +0 -5
- package/dist/esm/nextjs/middleware.js.map +1 -1
- package/dist/esm/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/esm/nextjs/routeHandler.js +7 -16
- package/dist/esm/nextjs/routeHandler.js.map +1 -1
- package/dist/esm/services/AuthenticationService.d.ts.map +1 -1
- package/dist/esm/services/AuthenticationService.js +0 -2
- package/dist/esm/services/AuthenticationService.js.map +1 -1
- package/dist/esm/shared/components/CivicAuthIframeContainer.js +2 -2
- package/dist/esm/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/esm/shared/hooks/useSignIn.js +2 -2
- package/dist/esm/shared/hooks/useSignIn.js.map +1 -1
- package/dist/esm/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
- package/dist/esm/shared/lib/GenericAuthenticationRefresher.js +0 -1
- package/dist/esm/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
- package/dist/esm/shared/lib/util.d.ts.map +1 -1
- package/dist/esm/shared/lib/util.js +0 -1
- package/dist/esm/shared/lib/util.js.map +1 -1
- package/dist/esm/shared/version.d.ts +1 -1
- package/dist/esm/shared/version.js +1 -1
- package/dist/esm/shared/version.js.map +1 -1
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# 0.2.2 authStatus and UserButton updates
|
|
2
2
|
- expose authStatus value from useUser
|
|
3
3
|
- show loading icon in UserButton, SignInButton and SignOutButton during sign in and sign out
|
|
4
|
+
- remove unnecessary logging
|
|
4
5
|
|
|
5
6
|
# 0.2.1 Server getTokens
|
|
6
7
|
- expose server/getTokens function
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postMessage.d.ts","sourceRoot":"","sources":["../../../src/lib/postMessage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,QAAA,MAAM,2BAA2B,UACxB,gBAAgB,YACb,MAAM,KACf,
|
|
1
|
+
{"version":3,"file":"postMessage.d.ts","sourceRoot":"","sources":["../../../src/lib/postMessage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,QAAA,MAAM,2BAA2B,UACxB,gBAAgB,YACb,MAAM,KACf,OAaF,CAAC;AAEF,OAAO,EAAE,2BAA2B,EAAE,CAAC"}
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.validateLoginAppPostMessage = void 0;
|
|
4
4
|
const validateLoginAppPostMessage = (event, clientId) => {
|
|
5
5
|
const caseEvent = event;
|
|
6
|
-
// console.log("caseEvent", caseEvent);
|
|
7
6
|
if (!caseEvent.clientId ||
|
|
8
7
|
!caseEvent.data.url ||
|
|
9
8
|
!caseEvent.source ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postMessage.js","sourceRoot":"","sources":["../../../src/lib/postMessage.ts"],"names":[],"mappings":";;;AAEA,MAAM,2BAA2B,GAAG,CAClC,KAAuB,EACvB,QAAgB,EACP,EAAE;IACX,MAAM,SAAS,GAAG,KAAyB,CAAC;IAC5C,
|
|
1
|
+
{"version":3,"file":"postMessage.js","sourceRoot":"","sources":["../../../src/lib/postMessage.ts"],"names":[],"mappings":";;;AAEA,MAAM,2BAA2B,GAAG,CAClC,KAAuB,EACvB,QAAgB,EACP,EAAE;IACX,MAAM,SAAS,GAAG,KAAyB,CAAC;IAC5C,IACE,CAAC,SAAS,CAAC,QAAQ;QACnB,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG;QACnB,CAAC,SAAS,CAAC,MAAM;QACjB,CAAC,SAAS,CAAC,IAAI;QACf,SAAS,CAAC,QAAQ,KAAK,QAAQ;QAC/B,SAAS,CAAC,MAAM,KAAK,eAAe,EACpC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEO,kEAA2B","sourcesContent":["import type { LoginPostMessage } from \"@/types.js\";\n\nconst validateLoginAppPostMessage = (\n event: LoginPostMessage,\n clientId: string,\n): boolean => {\n const caseEvent = event as LoginPostMessage;\n if (\n !caseEvent.clientId ||\n !caseEvent.data.url ||\n !caseEvent.source ||\n !caseEvent.type ||\n caseEvent.clientId !== clientId ||\n caseEvent.source !== \"civicloginApp\"\n ) {\n return false;\n }\n return true;\n};\n\nexport { validateLoginAppPostMessage };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AA8D1C;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,gBACZ,OAAO,CAAC,UAAU,CAAC,eAChB,WAAW,KAAG,OAAO,CAAC,YAAY,CAOjD,CAAC;AAEJ;;;;;;;GAOG;AAEH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,UAAU,GACrB,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAEjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,UAAU,GAAE,UAAe,gBAEhC,UAAU,KACrB,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CAQrD"}
|
|
@@ -26,11 +26,6 @@ const matchGlob = (pathname, globPattern) => {
|
|
|
26
26
|
const matchesGlobs = (pathname, patterns) => patterns.some((pattern) => {
|
|
27
27
|
if (!pattern)
|
|
28
28
|
return false;
|
|
29
|
-
console.log("matching", {
|
|
30
|
-
pattern,
|
|
31
|
-
pathname,
|
|
32
|
-
match: matchGlob(pathname, pattern),
|
|
33
|
-
});
|
|
34
29
|
return matchGlob(pathname, pattern);
|
|
35
30
|
});
|
|
36
31
|
// internal - used by all exported functions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/nextjs/middleware.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/nextjs/middleware.ts"],"names":[],"mappings":";;;;;;AAuHA,4BAIC;AAaD,oBAWC;AA7HD,8CAA8C;AAC9C,0DAAkC;AAElC,kDAAuD;AAMvD,iBAAiB;AACjB,YAAY;AACZ,QAAQ;AACR,UAAU;AACV,gBAAgB;AAChB,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAE,WAAmB,EAAE,EAAE;IAC1D,MAAM,OAAO,GAAG,IAAA,mBAAS,EAAC,WAAW,CAAC,CAAC;IACvC,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,iBAAiB;AACjB,YAAY;AACZ,QAAQ;AACR,UAAU;AACV,gBAAgB;AAChB,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,QAAkB,EAAE,EAAE,CAC5D,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEL,4CAA4C;AAC5C,MAAM,SAAS,GAAG,KAAK,EACrB,UAAsB,EACtB,OAAoB,EACe,EAAE;IACrC,MAAM,sBAAsB,GAAG,IAAA,6BAAiB,EAAC,UAAU,CAAC,CAAC;IAC7D,iCAAiC;IACjC,MAAM,eAAe,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAE1D,4CAA4C;IAC5C,IACE,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,QAAQ;QAC5D,OAAO,CAAC,MAAM,KAAK,KAAK,EACxB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAC7D,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3E,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;QAChE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,8BAA8B;IAC9B,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,+CAA+C,EAAE,QAAQ,CAAC,CAAC;QACvE,OAAO,wBAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;;;GAOG;AACI,MAAM,cAAc,GACzB,CAAC,aAAkC,EAAE,EAAE,EAAE,CACzC,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,wBAAY,CAAC,IAAI,EAAE,CAAC;AAC7B,CAAC,CAAC;AATS,QAAA,cAAc,kBASvB;AAEJ;;;;;;;GAOG;AACH,sDAAsD;AACtD,SAAgB,QAAQ,CACtB,UAAsB;IAEtB,OAAO,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,IAAI,CAAC,aAAyB,EAAE;IAC9C,OAAO,CACL,UAAsB,EAC6B,EAAE;QACrD,OAAO,KAAK,EAAE,OAAoB,EAAyB,EAAE;YAC3D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACtD,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YAE9B,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * console.log('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 * console.log('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport type { AuthConfig } from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n return matchGlob(pathname, pattern);\n });\n\n// internal - used by all exported functions\nconst applyAuth = async (\n authConfig: AuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n // Check for any valid auth token\n const isAuthenticated = !!request.cookies.get(\"id_token\");\n\n // skip auth check for redirect to login url\n if (\n request.nextUrl.pathname === authConfigWithDefaults.loginUrl &&\n request.method === \"GET\"\n ) {\n console.log(\"→ Skipping auth check - this is the login URL\");\n return undefined;\n }\n\n if (!matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)) {\n console.log(\"→ Skipping auth check - path not in include patterns\");\n return undefined;\n }\n\n if (matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)) {\n console.log(\"→ Skipping auth check - path in exclude patterns\");\n return undefined;\n }\n\n // Check for either token type\n if (!isAuthenticated) {\n const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.url);\n console.log(\"→ No valid token found - redirecting to login\", loginUrl);\n return NextResponse.redirect(loginUrl);\n }\n\n console.log(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig: Partial<AuthConfig> = {}) =>\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 * console.log('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return auth()(middleware);\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * export default auth(authConfig: AuthConfig ) => {\n * console.log('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: AuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n return middleware(request);\n };\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeHandler.d.ts","sourceRoot":"","sources":["../../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAgBrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"routeHandler.d.ts","sourceRoot":"","sources":["../../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAgBrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA4Q9C,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAwBvB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CA8DvB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,iCAEF,WAAW,KAAG,OAAO,CAAC,YAAY,CAkCjD,CAAC"}
|
|
@@ -112,7 +112,6 @@ const generateHtmlResponseWithCallback = (request, callbackUrl) => {
|
|
|
112
112
|
};
|
|
113
113
|
async function handleCallback(request, config) {
|
|
114
114
|
const resolvedConfigs = (0, config_js_1.resolveAuthConfig)(config);
|
|
115
|
-
console.log("handleCallback", { request, resolvedConfigs });
|
|
116
115
|
const code = request.nextUrl.searchParams.get("code");
|
|
117
116
|
const state = request.nextUrl.searchParams.get("state");
|
|
118
117
|
if (!code || !state)
|
|
@@ -125,14 +124,9 @@ async function handleCallback(request, config) {
|
|
|
125
124
|
// Otherwise, just render an empty page.
|
|
126
125
|
// The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.
|
|
127
126
|
// The client will make an additional call to this route with cookies included, at which point we do the token exchange.
|
|
128
|
-
console.log("handleCallback", {
|
|
129
|
-
code,
|
|
130
|
-
state,
|
|
131
|
-
appUrl,
|
|
132
|
-
});
|
|
133
127
|
const codeVerifier = request.cookies.get(types_js_1.CodeVerifier.COOKIE_NAME);
|
|
134
128
|
if (!codeVerifier || !appUrl) {
|
|
135
|
-
|
|
129
|
+
logger.debug("handleCallback no code_verifier found", {
|
|
136
130
|
state,
|
|
137
131
|
serverTokenExchange: (0, oauth_js_1.serverTokenExchangeFromState)(`${state}`),
|
|
138
132
|
});
|
|
@@ -142,7 +136,7 @@ async function handleCallback(request, config) {
|
|
|
142
136
|
// we only need to do this in redirect mode, as the iframe already triggers a client-side token exchange
|
|
143
137
|
// if no code-verifier cookie is found
|
|
144
138
|
if (state && (0, oauth_js_1.serverTokenExchangeFromState)(state)) {
|
|
145
|
-
|
|
139
|
+
logger.debug("handleCallback serverTokenExchangeFromState, launching redirect page...", {
|
|
146
140
|
requestUrl: request.url,
|
|
147
141
|
configCallbackUrl: resolvedConfigs.callbackUrl,
|
|
148
142
|
});
|
|
@@ -151,12 +145,12 @@ async function handleCallback(request, config) {
|
|
|
151
145
|
response = generateHtmlResponseWithCallback(request, resolvedConfigs.callbackUrl);
|
|
152
146
|
}
|
|
153
147
|
response.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
154
|
-
|
|
148
|
+
logger.debug(`handleCallback no code_verifier found, returning ${constants_js_1.TOKEN_EXCHANGE_TRIGGER_TEXT}`);
|
|
155
149
|
return response;
|
|
156
150
|
}
|
|
157
151
|
await performTokenExchangeAndSetCookies(request, resolvedConfigs, code, state, appUrl);
|
|
158
152
|
if (request.url.includes("sameDomainCallback=true")) {
|
|
159
|
-
|
|
153
|
+
logger.debug("handleCallback sameDomainCallback = true, returning redirectUrl", appUrl);
|
|
160
154
|
return server_js_1.NextResponse.json({
|
|
161
155
|
status: "success",
|
|
162
156
|
redirectUrl: appUrl,
|
|
@@ -164,7 +158,7 @@ async function handleCallback(request, config) {
|
|
|
164
158
|
}
|
|
165
159
|
// this is the case where a 'normal' redirect is happening
|
|
166
160
|
if ((0, oauth_js_1.serverTokenExchangeFromState)(state)) {
|
|
167
|
-
|
|
161
|
+
logger.debug("handleCallback serverTokenExchangeFromState, redirect to appUrl", appUrl);
|
|
168
162
|
if (!appUrl) {
|
|
169
163
|
throw new Error("appUrl undefined. Cannot redirect.");
|
|
170
164
|
}
|
|
@@ -212,7 +206,6 @@ const revalidateUrlPath = async (url) => {
|
|
|
212
206
|
}
|
|
213
207
|
};
|
|
214
208
|
async function handleLogout(request, config) {
|
|
215
|
-
console.log("handleLogout", { params: request.nextUrl.searchParams });
|
|
216
209
|
const resolvedConfigs = (0, config_js_1.resolveAuthConfig)(config);
|
|
217
210
|
// read the id_token from the cookies
|
|
218
211
|
const idToken = await getIdToken(resolvedConfigs);
|
|
@@ -236,7 +229,6 @@ async function handleLogoutCallback(request, config) {
|
|
|
236
229
|
if (!state)
|
|
237
230
|
throw new AuthError("Bad parameters", 400);
|
|
238
231
|
const displayMode = (0, oauth_js_1.displayModeFromState)(state, "iframe");
|
|
239
|
-
console.log("handleLogout: clear auth cookies", { state, displayMode });
|
|
240
232
|
const canAccessCookies = !!(await getIdToken(resolvedConfigs));
|
|
241
233
|
if (canAccessCookies) {
|
|
242
234
|
await (0, cookies_js_1.clearAuthCookies)(resolvedConfigs);
|
|
@@ -259,10 +251,9 @@ async function handleLogoutCallback(request, config) {
|
|
|
259
251
|
// handle logout for non-iframe display mode
|
|
260
252
|
const redirectUrl = getPostLogoutRedirectUrl(request, resolvedConfigs);
|
|
261
253
|
if (redirectUrl && canAccessCookies) {
|
|
262
|
-
console.log("handleLogout with redirect mode", { state, redirectUrl });
|
|
263
254
|
// this is comming from the fetch from the HTML page returned by this handler
|
|
264
255
|
if (request.url.includes("sameDomainCallback=true")) {
|
|
265
|
-
|
|
256
|
+
logger.debug("handleCallback sameDomainCallback = true, returning redirectUrl", redirectUrl);
|
|
266
257
|
return server_js_1.NextResponse.json({
|
|
267
258
|
status: "success",
|
|
268
259
|
redirectUrl: redirectUrl,
|
|
@@ -273,7 +264,7 @@ async function handleLogoutCallback(request, config) {
|
|
|
273
264
|
revalidateUrlPath(redirectUrl);
|
|
274
265
|
}
|
|
275
266
|
else {
|
|
276
|
-
|
|
267
|
+
logger.debug("handleLogout no redirectUrl found", { state });
|
|
277
268
|
response = generateHtmlResponseWithCallback(request, resolvedConfigs.logoutCallbackUrl);
|
|
278
269
|
response.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
279
270
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeHandler.js","sourceRoot":"","sources":["../../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport {\n displayModeFromState,\n serverTokenExchangeFromState,\n} from \"@/lib/oauth.js\";\nimport type { AuthConfig } from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport {\n clearAuthCookies,\n NextjsClientStorage,\n NextjsCookieStorage,\n} from \"@/nextjs/cookies.js\";\nimport { getUser } from \"@/nextjs/index.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { AuthenticationRefresherImpl } from \"@/shared/lib/AuthenticationRefresherImpl.js\";\nimport { CodeVerifier, OAuthTokens } from \"@/shared/lib/types.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\nimport { revalidatePath } from \"next/cache.js\";\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nclass AuthError extends Error {\n constructor(\n message: string,\n public readonly status: number = 401,\n ) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nconst getAppUrl = (request: NextRequest): string | null =>\n request.cookies.get(CodeVerifier.APP_URL)?.value ||\n request.nextUrl.searchParams.get(\"appUrl\");\n\nconst getIdToken = async (config: AuthConfig): Promise<string | null> => {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n return cookieStorage.get(OAuthTokens.ID_TOKEN);\n};\n\n/**\n * create a code verifier and challenge for PKCE\n * saving the verifier in a cookie for later use\n * @returns {Promise<NextResponse>}\n */\nasync function handleChallenge(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);\n\n const challenge = await pkceProducer.getCodeChallenge();\n const appUrl = request.nextUrl.searchParams.get(\"appUrl\");\n if (appUrl) {\n cookieStorage.set(CodeVerifier.APP_URL, appUrl);\n }\n return NextResponse.json({ status: \"success\", challenge });\n}\n\nasync function performTokenExchangeAndSetCookies(\n request: NextRequest,\n config: AuthConfig,\n code: string,\n state: string,\n appUrl: string,\n) {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = new NextjsCookieStorage(resolvedConfigs.cookies.tokens);\n\n const callbackUrl = resolveCallbackUrl(resolvedConfigs, appUrl);\n try {\n await resolveOAuthAccessCode(code, state, cookieStorage, {\n ...resolvedConfigs,\n redirectUrl: callbackUrl,\n });\n } catch (error) {\n logger.error(\"Token exchange failed:\", error);\n throw new AuthError(\"Failed to authenticate user\", 401);\n }\n\n const user = await getUser();\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(user);\n}\nasync function handleRefresh(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n\n const refresher = await AuthenticationRefresherImpl.build(\n {\n clientId: resolvedConfigs.clientId,\n oauthServer: resolvedConfigs.oauthServer,\n redirectUrl: resolvedConfigs.callbackUrl,\n refreshUrl: resolvedConfigs.refreshUrl,\n },\n cookieStorage,\n );\n const tokens = await refresher.refreshAccessToken();\n\n // this will use the refresh token to get new tokens and, if successful\n // the idToken, accessToken and user cookies will be updated\n // await newRefresher.refreshTokens();\n return NextResponse.json({ status: \"success\", tokens });\n}\n\nconst generateHtmlResponseWithCallback = (\n request: NextRequest,\n callbackUrl: string,\n) => {\n // we need to replace the URL with resolved config in case the server is hosted\n // behind a reverse proxy or load balancer\n const requestUrl = new URL(request.url);\n const fetchUrl = `${callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainCallback=true`;\n return new NextResponse(\n `<html>\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n const appUrl = globalThis.window?.location?.origin;\n fetch('${fetchUrl}&appUrl=' + appUrl).then((response) => {\n response.json().then((jsonResponse) => {\n if (jsonResponse.redirectUrl) {\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n </html>\n `,\n );\n};\n\nasync function handleCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n console.log(\"handleCallback\", { request, resolvedConfigs });\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n if (!code || !state) throw new AuthError(\"Bad parameters\", 400);\n\n // appUrl is passed from the client to the server in the query string\n // this is necessary because the server does not have access to the client's window.location.origin\n // and can not accurately determine the appUrl (specially if the app is behind a reverse proxy)\n const appUrl = getAppUrl(request);\n\n // If we have a code_verifier cookie and the appUrl, we can do a token exchange.\n // Otherwise, just render an empty page.\n // The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.\n // The client will make an additional call to this route with cookies included, at which point we do the token exchange.\n console.log(\"handleCallback\", {\n code,\n state,\n appUrl,\n });\n\n const codeVerifier = request.cookies.get(CodeVerifier.COOKIE_NAME);\n\n if (!codeVerifier || !appUrl) {\n console.log(\"handleCallback no code_verifier found\", {\n state,\n serverTokenExchange: serverTokenExchangeFromState(`${state}`),\n });\n let response = new NextResponse(\n `<html><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n );\n\n // in server-side token exchange mode we need to launch a page that will trigger the token exchange\n // from the same domain, allowing it access to the code_verifier cookie\n // we only need to do this in redirect mode, as the iframe already triggers a client-side token exchange\n // if no code-verifier cookie is found\n if (state && serverTokenExchangeFromState(state)) {\n console.log(\n \"handleCallback serverTokenExchangeFromState, launching redirect page...\",\n {\n requestUrl: request.url,\n configCallbackUrl: resolvedConfigs.callbackUrl,\n },\n );\n // generate a page that will callback to the same domain, allowing access\n // to the code_verifier cookie and passing the appUrl.\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.callbackUrl,\n );\n }\n\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n console.log(\n `handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`,\n );\n return response;\n }\n\n await performTokenExchangeAndSetCookies(\n request,\n resolvedConfigs,\n code,\n state,\n appUrl,\n );\n\n if (request.url.includes(\"sameDomainCallback=true\")) {\n console.log(\n \"handleCallback sameDomainCallback = true, returnining redirectUrl\",\n appUrl,\n );\n return NextResponse.json({\n status: \"success\",\n redirectUrl: appUrl,\n });\n }\n\n // this is the case where a 'normal' redirect is happening\n if (serverTokenExchangeFromState(state)) {\n console.log(\n \"handleCallback serverTokenExchangeFromState, redirect to appUrl\",\n appUrl,\n );\n if (!appUrl) {\n throw new Error(\"appUrl undefined. Cannot redirect.\");\n }\n return NextResponse.redirect(`${appUrl}`);\n }\n // return an empty HTML response so the iframe doesn't show any response\n // in the short moment between the redirect and the parent window\n // acknowledging the redirect and closing the iframe\n const response = new NextResponse(\n `<html><span style=\"display:none\">${TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n}\n\n/**\n * If redirectPath is an absolute path, return it as-is.\n * Otherwise for relative paths, append it to the current domain.\n * @param redirectPath\n * @returns\n */\nconst getAbsoluteRedirectPath = (\n redirectPath: string,\n currentBasePath: string,\n) => new URL(redirectPath, currentBasePath).href;\n\nconst getPostLogoutRedirectUrl = (\n request: NextRequest,\n config: AuthConfig,\n): string | null => {\n const { loginUrl } = resolveAuthConfig(config);\n const redirectTarget = loginUrl ?? \"/\";\n\n // if the optional loginUrl is provided and it is an absolute URL,\n // use it as the redirect target\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n if (isAbsoluteRedirect) {\n return redirectTarget;\n }\n\n // if loginUrl is not defined, the appUrl is passed from the client to the server\n // in the query string or cookies. This is necessary because the server does not\n // have access to the client's window.location and can not accurately determine\n // the appUrl (specially if the app is behind a reverse proxy).\n const appUrl = getAppUrl(request);\n if (appUrl) return getAbsoluteRedirectPath(redirectTarget, appUrl);\n\n return null;\n};\n\nconst revalidateUrlPath = async (url: string) => {\n try {\n const path = new URL(url).pathname;\n revalidatePath(path);\n } catch (error) {\n logger.warn(\"Failed to revalidate path after logout:\", error);\n }\n};\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n console.log(\"handleLogout\", { params: request.nextUrl.searchParams });\n const resolvedConfigs = resolveAuthConfig(config);\n\n // read the id_token from the cookies\n const idToken = await getIdToken(resolvedConfigs);\n\n // read the state from the query parameters\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!state || !idToken) throw new AuthError(`Bad parameters`, 400);\n\n const postLogoutUrl = new URL(\n resolvedConfigs.logoutCallbackUrl,\n getAppUrl(request) || request.url,\n );\n const logoutUrl = await generateOauthLogoutUrl({\n clientId: resolvedConfigs.clientId,\n idToken,\n state,\n redirectUrl: postLogoutUrl.href,\n oauthServer: resolvedConfigs.oauthServer,\n });\n\n return NextResponse.redirect(`${logoutUrl.href}`);\n}\n\nexport async function handleLogoutCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const state = request.nextUrl.searchParams.get(\"state\") || \"\";\n if (!state) throw new AuthError(\"Bad parameters\", 400);\n\n const displayMode = displayModeFromState(state, \"iframe\");\n\n console.log(\"handleLogout: clear auth cookies\", { state, displayMode });\n\n const canAccessCookies = !!(await getIdToken(resolvedConfigs));\n if (canAccessCookies) {\n await clearAuthCookies(resolvedConfigs);\n }\n\n let response;\n\n // handle logout for iframe display mode\n if (displayMode === \"iframe\") {\n // try to read the token from cookies. If cookies cant be read/written\n // because the request cames from a cross-origin redirect,\n // we need to show a page that will trigger the logout from the same domain\n if (canAccessCookies || request.url.includes(\"sameDomainCallback=true\")) {\n // just return success\n return NextResponse.json({ status: \"success\" });\n }\n\n // return a page that will trigger the logout from the same domain\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.logoutCallbackUrl,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n }\n\n // handle logout for non-iframe display mode\n const redirectUrl = getPostLogoutRedirectUrl(request, resolvedConfigs);\n\n if (redirectUrl && canAccessCookies) {\n console.log(\"handleLogout with redirect mode\", { state, redirectUrl });\n\n // this is comming from the fetch from the HTML page returned by this handler\n if (request.url.includes(\"sameDomainCallback=true\")) {\n console.log(\n \"handleCallback sameDomainCallback = true, returnining redirectUrl\",\n redirectUrl,\n );\n return NextResponse.json({\n status: \"success\",\n redirectUrl: redirectUrl,\n });\n }\n\n // just redirect to the app url\n response = NextResponse.redirect(`${redirectUrl}`);\n revalidateUrlPath(redirectUrl);\n } else {\n console.log(\"handleLogout no redirectUrl found\", { state });\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.logoutCallbackUrl,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n }\n\n return response;\n}\n\n/**\n * Creates an authentication handler for Next.js API routes\n *\n * Usage:\n * ```ts\n * // app/api/auth/[...civicauth]/route.ts\n * import { handler } from '@civic/auth/nextjs'\n * export const GET = handler({\n * // optional config overrides\n * })\n * ```\n */\nexport const handler =\n (authConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const config = resolveAuthConfig(authConfig);\n\n try {\n const pathname = request.nextUrl.pathname;\n const pathSegments = pathname.split(\"/\");\n const lastSegment = pathSegments[pathSegments.length - 1];\n\n switch (lastSegment) {\n case \"challenge\":\n return await handleChallenge(request, config);\n case \"callback\":\n return await handleCallback(request, config);\n case \"refresh\":\n return await handleRefresh(request, config);\n case \"logout\":\n return await handleLogout(request, config);\n case \"logoutcallback\":\n return await handleLogoutCallback(request, config);\n default:\n throw new AuthError(`Invalid auth route: ${pathname}`, 404);\n }\n } catch (error) {\n logger.error(\"Auth handler error:\", error);\n\n const status = error instanceof AuthError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : \"Authentication failed\";\n\n const response = NextResponse.json({ error: message }, { status });\n\n clearAuthCookies(config);\n return response;\n }\n };\n"]}
|
|
1
|
+
{"version":3,"file":"routeHandler.js","sourceRoot":"","sources":["../../../src/nextjs/routeHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport {\n displayModeFromState,\n serverTokenExchangeFromState,\n} from \"@/lib/oauth.js\";\nimport type { AuthConfig } from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport {\n clearAuthCookies,\n NextjsClientStorage,\n NextjsCookieStorage,\n} from \"@/nextjs/cookies.js\";\nimport { getUser } from \"@/nextjs/index.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { AuthenticationRefresherImpl } from \"@/shared/lib/AuthenticationRefresherImpl.js\";\nimport { CodeVerifier, OAuthTokens } from \"@/shared/lib/types.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\nimport { revalidatePath } from \"next/cache.js\";\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nclass AuthError extends Error {\n constructor(\n message: string,\n public readonly status: number = 401,\n ) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\nconst getAppUrl = (request: NextRequest): string | null =>\n request.cookies.get(CodeVerifier.APP_URL)?.value ||\n request.nextUrl.searchParams.get(\"appUrl\");\n\nconst getIdToken = async (config: AuthConfig): Promise<string | null> => {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n return cookieStorage.get(OAuthTokens.ID_TOKEN);\n};\n\n/**\n * create a code verifier and challenge for PKCE\n * saving the verifier in a cookie for later use\n * @returns {Promise<NextResponse>}\n */\nasync function handleChallenge(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);\n\n const challenge = await pkceProducer.getCodeChallenge();\n const appUrl = request.nextUrl.searchParams.get(\"appUrl\");\n if (appUrl) {\n cookieStorage.set(CodeVerifier.APP_URL, appUrl);\n }\n return NextResponse.json({ status: \"success\", challenge });\n}\n\nasync function performTokenExchangeAndSetCookies(\n request: NextRequest,\n config: AuthConfig,\n code: string,\n state: string,\n appUrl: string,\n) {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = new NextjsCookieStorage(resolvedConfigs.cookies.tokens);\n\n const callbackUrl = resolveCallbackUrl(resolvedConfigs, appUrl);\n try {\n await resolveOAuthAccessCode(code, state, cookieStorage, {\n ...resolvedConfigs,\n redirectUrl: callbackUrl,\n });\n } catch (error) {\n logger.error(\"Token exchange failed:\", error);\n throw new AuthError(\"Failed to authenticate user\", 401);\n }\n\n const user = await getUser();\n if (!user) {\n throw new AuthError(\"Failed to get user info\", 401);\n }\n\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(user);\n}\nasync function handleRefresh(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens ?? {});\n\n const refresher = await AuthenticationRefresherImpl.build(\n {\n clientId: resolvedConfigs.clientId,\n oauthServer: resolvedConfigs.oauthServer,\n redirectUrl: resolvedConfigs.callbackUrl,\n refreshUrl: resolvedConfigs.refreshUrl,\n },\n cookieStorage,\n );\n const tokens = await refresher.refreshAccessToken();\n\n // this will use the refresh token to get new tokens and, if successful\n // the idToken, accessToken and user cookies will be updated\n // await newRefresher.refreshTokens();\n return NextResponse.json({ status: \"success\", tokens });\n}\n\nconst generateHtmlResponseWithCallback = (\n request: NextRequest,\n callbackUrl: string,\n) => {\n // we need to replace the URL with resolved config in case the server is hosted\n // behind a reverse proxy or load balancer\n const requestUrl = new URL(request.url);\n const fetchUrl = `${callbackUrl}?${requestUrl.searchParams.toString()}&sameDomainCallback=true`;\n return new NextResponse(\n `<html>\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n const appUrl = globalThis.window?.location?.origin;\n fetch('${fetchUrl}&appUrl=' + appUrl).then((response) => {\n response.json().then((jsonResponse) => {\n if (jsonResponse.redirectUrl) {\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n </html>\n `,\n );\n};\n\nasync function handleCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n if (!code || !state) throw new AuthError(\"Bad parameters\", 400);\n\n // appUrl is passed from the client to the server in the query string\n // this is necessary because the server does not have access to the client's window.location.origin\n // and can not accurately determine the appUrl (specially if the app is behind a reverse proxy)\n const appUrl = getAppUrl(request);\n\n // If we have a code_verifier cookie and the appUrl, we can do a token exchange.\n // Otherwise, just render an empty page.\n // The initial redirect back from the auth server does not send cookies, because the redirect is from a 3rd-party domain.\n // The client will make an additional call to this route with cookies included, at which point we do the token exchange.\n const codeVerifier = request.cookies.get(CodeVerifier.COOKIE_NAME);\n\n if (!codeVerifier || !appUrl) {\n logger.debug(\"handleCallback no code_verifier found\", {\n state,\n serverTokenExchange: serverTokenExchangeFromState(`${state}`),\n });\n let response = new NextResponse(\n `<html><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n );\n\n // in server-side token exchange mode we need to launch a page that will trigger the token exchange\n // from the same domain, allowing it access to the code_verifier cookie\n // we only need to do this in redirect mode, as the iframe already triggers a client-side token exchange\n // if no code-verifier cookie is found\n if (state && serverTokenExchangeFromState(state)) {\n logger.debug(\n \"handleCallback serverTokenExchangeFromState, launching redirect page...\",\n {\n requestUrl: request.url,\n configCallbackUrl: resolvedConfigs.callbackUrl,\n },\n );\n // generate a page that will callback to the same domain, allowing access\n // to the code_verifier cookie and passing the appUrl.\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.callbackUrl,\n );\n }\n\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n logger.debug(\n `handleCallback no code_verifier found, returning ${TOKEN_EXCHANGE_TRIGGER_TEXT}`,\n );\n return response;\n }\n\n await performTokenExchangeAndSetCookies(\n request,\n resolvedConfigs,\n code,\n state,\n appUrl,\n );\n\n if (request.url.includes(\"sameDomainCallback=true\")) {\n logger.debug(\n \"handleCallback sameDomainCallback = true, returning redirectUrl\",\n appUrl,\n );\n return NextResponse.json({\n status: \"success\",\n redirectUrl: appUrl,\n });\n }\n\n // this is the case where a 'normal' redirect is happening\n if (serverTokenExchangeFromState(state)) {\n logger.debug(\n \"handleCallback serverTokenExchangeFromState, redirect to appUrl\",\n appUrl,\n );\n if (!appUrl) {\n throw new Error(\"appUrl undefined. Cannot redirect.\");\n }\n return NextResponse.redirect(`${appUrl}`);\n }\n // return an empty HTML response so the iframe doesn't show any response\n // in the short moment between the redirect and the parent window\n // acknowledging the redirect and closing the iframe\n const response = new NextResponse(\n `<html><span style=\"display:none\">${TOKEN_EXCHANGE_SUCCESS_TEXT}</span></html>`,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n}\n\n/**\n * If redirectPath is an absolute path, return it as-is.\n * Otherwise for relative paths, append it to the current domain.\n * @param redirectPath\n * @returns\n */\nconst getAbsoluteRedirectPath = (\n redirectPath: string,\n currentBasePath: string,\n) => new URL(redirectPath, currentBasePath).href;\n\nconst getPostLogoutRedirectUrl = (\n request: NextRequest,\n config: AuthConfig,\n): string | null => {\n const { loginUrl } = resolveAuthConfig(config);\n const redirectTarget = loginUrl ?? \"/\";\n\n // if the optional loginUrl is provided and it is an absolute URL,\n // use it as the redirect target\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n if (isAbsoluteRedirect) {\n return redirectTarget;\n }\n\n // if loginUrl is not defined, the appUrl is passed from the client to the server\n // in the query string or cookies. This is necessary because the server does not\n // have access to the client's window.location and can not accurately determine\n // the appUrl (specially if the app is behind a reverse proxy).\n const appUrl = getAppUrl(request);\n if (appUrl) return getAbsoluteRedirectPath(redirectTarget, appUrl);\n\n return null;\n};\n\nconst revalidateUrlPath = async (url: string) => {\n try {\n const path = new URL(url).pathname;\n revalidatePath(path);\n } catch (error) {\n logger.warn(\"Failed to revalidate path after logout:\", error);\n }\n};\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n\n // read the id_token from the cookies\n const idToken = await getIdToken(resolvedConfigs);\n\n // read the state from the query parameters\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!state || !idToken) throw new AuthError(`Bad parameters`, 400);\n\n const postLogoutUrl = new URL(\n resolvedConfigs.logoutCallbackUrl,\n getAppUrl(request) || request.url,\n );\n const logoutUrl = await generateOauthLogoutUrl({\n clientId: resolvedConfigs.clientId,\n idToken,\n state,\n redirectUrl: postLogoutUrl.href,\n oauthServer: resolvedConfigs.oauthServer,\n });\n\n return NextResponse.redirect(`${logoutUrl.href}`);\n}\n\nexport async function handleLogoutCallback(\n request: NextRequest,\n config: AuthConfig,\n): Promise<NextResponse> {\n const resolvedConfigs = resolveAuthConfig(config);\n const state = request.nextUrl.searchParams.get(\"state\") || \"\";\n if (!state) throw new AuthError(\"Bad parameters\", 400);\n\n const displayMode = displayModeFromState(state, \"iframe\");\n\n const canAccessCookies = !!(await getIdToken(resolvedConfigs));\n if (canAccessCookies) {\n await clearAuthCookies(resolvedConfigs);\n }\n\n let response;\n\n // handle logout for iframe display mode\n if (displayMode === \"iframe\") {\n // try to read the token from cookies. If cookies cant be read/written\n // because the request cames from a cross-origin redirect,\n // we need to show a page that will trigger the logout from the same domain\n if (canAccessCookies || request.url.includes(\"sameDomainCallback=true\")) {\n // just return success\n return NextResponse.json({ status: \"success\" });\n }\n\n // return a page that will trigger the logout from the same domain\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.logoutCallbackUrl,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n return response;\n }\n\n // handle logout for non-iframe display mode\n const redirectUrl = getPostLogoutRedirectUrl(request, resolvedConfigs);\n\n if (redirectUrl && canAccessCookies) {\n // this is comming from the fetch from the HTML page returned by this handler\n if (request.url.includes(\"sameDomainCallback=true\")) {\n logger.debug(\n \"handleCallback sameDomainCallback = true, returning redirectUrl\",\n redirectUrl,\n );\n return NextResponse.json({\n status: \"success\",\n redirectUrl: redirectUrl,\n });\n }\n\n // just redirect to the app url\n response = NextResponse.redirect(`${redirectUrl}`);\n revalidateUrlPath(redirectUrl);\n } else {\n logger.debug(\"handleLogout no redirectUrl found\", { state });\n response = generateHtmlResponseWithCallback(\n request,\n resolvedConfigs.logoutCallbackUrl,\n );\n response.headers.set(\"Content-Type\", \"text/html; charset=utf-8\");\n }\n\n return response;\n}\n\n/**\n * Creates an authentication handler for Next.js API routes\n *\n * Usage:\n * ```ts\n * // app/api/auth/[...civicauth]/route.ts\n * import { handler } from '@civic/auth/nextjs'\n * export const GET = handler({\n * // optional config overrides\n * })\n * ```\n */\nexport const handler =\n (authConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const config = resolveAuthConfig(authConfig);\n\n try {\n const pathname = request.nextUrl.pathname;\n const pathSegments = pathname.split(\"/\");\n const lastSegment = pathSegments[pathSegments.length - 1];\n\n switch (lastSegment) {\n case \"challenge\":\n return await handleChallenge(request, config);\n case \"callback\":\n return await handleCallback(request, config);\n case \"refresh\":\n return await handleRefresh(request, config);\n case \"logout\":\n return await handleLogout(request, config);\n case \"logoutcallback\":\n return await handleLogoutCallback(request, config);\n default:\n throw new AuthError(`Invalid auth route: ${pathname}`, 404);\n }\n } catch (error) {\n logger.error(\"Auth handler error:\", error);\n\n const status = error instanceof AuthError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : \"Authentication failed\";\n\n const response = NextResponse.json({ error: message }, { status });\n\n clearAuthCookies(config);\n return response;\n }\n };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationService.d.ts","sourceRoot":"","sources":["../../../src/services/AuthenticationService.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EAGT,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,+BAA+B,EAEhC,MAAM,oBAAoB,CAAC;AAe5B,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,YAAY,EACb,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,MAAM,oCAAoC,GAAG;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAEvC,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,IAAI,CACrD,oCAAoC,EACpC,OAAO,CACR,GAAG;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAE1B,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AACF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,8BAA+B,YAAW,uBAAuB;IAC5E,OAAO,CAAC,kBAAkB,CAAgD;IAE1E,SAAS,CAAC,MAAM,EAAE,oCAAoC,CAAC;IAEhD,cAAc,CAAC,WAAW,EAAE,WAAW;IAI9C,IAAI,WAAW,gBAEd;IAED,IAAI,qBAAqB,YAExB;IACD,IAAI,KAAK,WAER;gBACW,MAAM,EAAE,OAAO,IAAI,CAAC,MAAM;IAIhC,yBAAyB,CAAC,WAAW,EAAE,MAAM;IAU7C,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC;IAkD/D,SAAS,CAAC,qBAAqB,CAC7B,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"AuthenticationService.d.ts","sourceRoot":"","sources":["../../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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"}
|
|
@@ -105,7 +105,6 @@ class BrowserAuthenticationInitiator {
|
|
|
105
105
|
const messageHandler = (event) => {
|
|
106
106
|
if (event.source !== iframe.contentWindow) {
|
|
107
107
|
// This message did not originate from the iframe. Ignore it.
|
|
108
|
-
console.log("Message did not originate from the iframe. Ignoring it.");
|
|
109
108
|
return;
|
|
110
109
|
}
|
|
111
110
|
const message = event.data;
|
|
@@ -137,7 +136,6 @@ class BrowserAuthenticationInitiator {
|
|
|
137
136
|
}
|
|
138
137
|
catch (e) {
|
|
139
138
|
// Ignore cross-origin errors
|
|
140
|
-
console.log("Cross-origin error", e);
|
|
141
139
|
}
|
|
142
140
|
};
|
|
143
141
|
interval = setInterval(checkIframe, 100);
|
|
@@ -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 IframeAuthMessage,\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 { 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 { DEFAULT_OAUTH_GET_PARAMS } from \"@/constants.js\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage.js\";\nimport { getUser } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\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 // used to get the PKCE challenge\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};\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\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(this.config.displayMode, this.isServerTokenExchange);\n }\n constructor(config: typeof this.config) {\n this.config = config;\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 // 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 const url = await generateOauthLoginUrl({\n ...this.config,\n state: this.state,\n });\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 this.handleLoginAppPopupFailed(loginMessage.data.url);\n }\n };\n\n window.addEventListener(\"message\", this.postMessageHandler);\n\n if (this.config.displayMode === \"iframe\") {\n if (!iframeRef)\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n iframeRef.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 protected handleIframeUrlChange(\n iframe: HTMLIFrameElement,\n expectedUrl: string,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n let interval: NodeJS.Timeout | undefined = undefined;\n let timeout: NodeJS.Timeout | undefined = undefined;\n\n const messageHandler = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) {\n // This message did not originate from the iframe. Ignore it.\n console.log(\n \"Message did not originate from the iframe. Ignoring it.\",\n );\n return;\n }\n\n const message = event.data as IframeAuthMessage;\n\n if (\n message.source === \"civicloginApp\" &&\n message.type === \"auth_error\"\n ) {\n clearInterval(interval);\n clearTimeout(timeout);\n return;\n }\n\n if (\n message.source === \"civicloginApp\" &&\n message.type === \"auth_error_try_again\"\n ) {\n clearInterval(interval);\n clearTimeout(timeout);\n window.removeEventListener(\"message\", messageHandler);\n reject(new Error(message.data.error || \"Authentication failed\"));\n return;\n }\n };\n\n window.addEventListener(\"message\", messageHandler);\n\n // Keep the existing URL check logic for success case\n const checkIframe = () => {\n try {\n const currentUrl = iframe.contentWindow?.location.href;\n if (currentUrl?.includes(expectedUrl)) {\n clearInterval(interval);\n window.removeEventListener(\"message\", messageHandler);\n resolve();\n }\n } catch (e) {\n // Ignore cross-origin errors\n console.log(\"Cross-origin error\", e);\n }\n };\n\n interval = setInterval(checkIframe, 100);\n\n // Timeout after 10 seconds\n timeout = setTimeout(() => {\n clearInterval(interval);\n window.removeEventListener(\"message\", messageHandler);\n reject(new Error(\"Timeout waiting for iframe URL change\"));\n }, 10000);\n });\n }\n\n async signOut(\n idToken: string | undefined,\n iframeRef: HTMLIFrameElement | null,\n ): Promise<URL> {\n let url;\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 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 if (!iframeRef) {\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n }\n iframeRef.setAttribute(\"src\", url.toString());\n\n await this.handleIframeUrlChange(\n iframeRef,\n this.config.logoutRedirectUrl,\n );\n\n // Clear storage after successful detection\n if (!this.isServerTokenExchange) {\n const localStorage = new LocalStorageAdapter();\n await clearTokens(localStorage);\n await clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n }\n }\n\n if (this.config.displayMode === \"redirect\") {\n const localStorage = new LocalStorageAdapter();\n localStorage.set(\"logout_state\", state);\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 } 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.config.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 // 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.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n const clientStorage = new LocalStorageAdapter();\n await storeTokens(clientStorage, tokens);\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 // 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\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 };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n // await clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n if (!this.endpoints || !this.oauth2client) await this.init();\n\n // this function will throw if any of the tokens are invalid\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken,\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n },\n this.endpoints!,\n this.oauth2client!,\n this.config.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 await clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\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 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 IframeAuthMessage,\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 { 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 { DEFAULT_OAUTH_GET_PARAMS } from \"@/constants.js\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage.js\";\nimport { getUser } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\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 // used to get the PKCE challenge\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};\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\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(this.config.displayMode, this.isServerTokenExchange);\n }\n constructor(config: typeof this.config) {\n this.config = config;\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 // 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 const url = await generateOauthLoginUrl({\n ...this.config,\n state: this.state,\n });\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 this.handleLoginAppPopupFailed(loginMessage.data.url);\n }\n };\n\n window.addEventListener(\"message\", this.postMessageHandler);\n\n if (this.config.displayMode === \"iframe\") {\n if (!iframeRef)\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n iframeRef.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 protected handleIframeUrlChange(\n iframe: HTMLIFrameElement,\n expectedUrl: string,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n let interval: NodeJS.Timeout | undefined = undefined;\n let timeout: NodeJS.Timeout | undefined = undefined;\n\n const messageHandler = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) {\n // This message did not originate from the iframe. Ignore it.\n return;\n }\n\n const message = event.data as IframeAuthMessage;\n\n if (\n message.source === \"civicloginApp\" &&\n message.type === \"auth_error\"\n ) {\n clearInterval(interval);\n clearTimeout(timeout);\n return;\n }\n\n if (\n message.source === \"civicloginApp\" &&\n message.type === \"auth_error_try_again\"\n ) {\n clearInterval(interval);\n clearTimeout(timeout);\n window.removeEventListener(\"message\", messageHandler);\n reject(new Error(message.data.error || \"Authentication failed\"));\n return;\n }\n };\n\n window.addEventListener(\"message\", messageHandler);\n\n // Keep the existing URL check logic for success case\n const checkIframe = () => {\n try {\n const currentUrl = iframe.contentWindow?.location.href;\n if (currentUrl?.includes(expectedUrl)) {\n clearInterval(interval);\n window.removeEventListener(\"message\", messageHandler);\n resolve();\n }\n } catch (e) {\n // Ignore cross-origin errors\n }\n };\n\n interval = setInterval(checkIframe, 100);\n\n // Timeout after 10 seconds\n timeout = setTimeout(() => {\n clearInterval(interval);\n window.removeEventListener(\"message\", messageHandler);\n reject(new Error(\"Timeout waiting for iframe URL change\"));\n }, 10000);\n });\n }\n\n async signOut(\n idToken: string | undefined,\n iframeRef: HTMLIFrameElement | null,\n ): Promise<URL> {\n let url;\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 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 if (!iframeRef) {\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n }\n iframeRef.setAttribute(\"src\", url.toString());\n\n await this.handleIframeUrlChange(\n iframeRef,\n this.config.logoutRedirectUrl,\n );\n\n // Clear storage after successful detection\n if (!this.isServerTokenExchange) {\n const localStorage = new LocalStorageAdapter();\n await clearTokens(localStorage);\n await clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n }\n }\n\n if (this.config.displayMode === \"redirect\") {\n const localStorage = new LocalStorageAdapter();\n localStorage.set(\"logout_state\", state);\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 } 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.config.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 // 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.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n const clientStorage = new LocalStorageAdapter();\n await storeTokens(clientStorage, tokens);\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 // 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\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 };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n // await clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n if (!this.endpoints || !this.oauth2client) await this.init();\n\n // this function will throw if any of the tokens are invalid\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken,\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n },\n this.endpoints!,\n this.oauth2client!,\n this.config.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 await clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\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 config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
|
|
@@ -135,8 +135,8 @@ const CivicAuthIframeContainer = ({ onClose, closeOnRedirect = true, }) => {
|
|
|
135
135
|
return true; // Successfully processed the URL
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
-
catch
|
|
139
|
-
|
|
138
|
+
catch {
|
|
139
|
+
// ignore errors while waiting for redirect
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
return false; // Haven't processed the URL yet
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CivicAuthIframeContainer.js","sourceRoot":"","sources":["../../../../src/shared/components/CivicAuthIframeContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { CloseIcon } from \"@/shared/components/CloseIcon.js\";\nimport { CivicAuthIframe } from \"@/shared/components/CivicAuthIframe.js\";\nimport { useIframe } from \"@/shared/hooks/index.js\";\nimport { TOKEN_EXCHANGE_TRIGGER_TEXT } from \"@/constants.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/index.js\";\nimport { useClientTokenExchangeSession } from \"@/shared/hooks/index.js\";\nimport { useSession } from \"@/shared/hooks/index.js\";\n\ntype CivicAuthIframeContainerProps = {\n onClose?: () => void;\n closeOnRedirect?: boolean;\n};\n\nfunction NoChrome({\n children,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return <div style={{ position: \"relative\" }}>{children}</div>;\n}\n\nexport function IframeChrome({\n children,\n onClose,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n const { setIframeAborted } = useIframe();\n return (\n <div\n style={{\n position: \"fixed\", // Change to fixed to stay in viewport\n left: 0,\n top: 0,\n zIndex: 50,\n display: \"flex\",\n height: \"100vh\",\n width: \"100vw\",\n minWidth: \"18rem\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(17, 24, 39, 0.5)\", // Semi-transparent dark background\n backdropFilter: \"blur(4px)\", // Optional: adds slight blur to background\n }}\n onClick={onClose}\n >\n <div\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n borderRadius: \"1.5rem\",\n backgroundColor: \"white\",\n padding: \"1.5rem\",\n boxShadow:\n \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n style={{\n position: \"absolute\",\n right: \"1rem\",\n top: \"1rem\",\n display: \"flex\",\n cursor: \"pointer\",\n alignItems: \"center\",\n justifyContent: \"center\",\n border: \"none\",\n backgroundColor: \"transparent\",\n padding: \"0.25rem\",\n color: \"#9ca3af\",\n }}\n onClick={() => {\n setIframeAborted(true);\n onClose?.();\n }}\n >\n <CloseIcon />\n </button>\n\n {children}\n </div>\n </div>\n );\n}\n\nconst CivicAuthIframeContainer = ({\n onClose,\n closeOnRedirect = true,\n}: CivicAuthIframeContainerProps) => {\n const [isLoading, setIsLoading] = useState(true);\n const { isLoading: isAuthLoading, data: session } = useSession();\n const config = useCivicAuthConfig();\n const [tokenExchangeUrl, setTokenExchangeUrl] = useState<string | null>(null);\n const { doTokenExchange } = useClientTokenExchangeSession();\n const { iframeRef, iframeMode } = useIframe();\n\n useEffect(() => {\n if (tokenExchangeUrl) {\n doTokenExchange?.(tokenExchangeUrl);\n }\n }, [doTokenExchange, tokenExchangeUrl]);\n\n const processIframeUrl = useCallback(() => {\n if (!config) return;\n if (iframeRef && iframeRef.current && iframeRef.current.contentWindow) {\n try {\n const iframeUrl = iframeRef.current.contentWindow.location.href;\n // we know that oauth has finished when the iframe redirects to our redirectUrl\n if (iframeUrl.startsWith(config.redirectUrl)) {\n // we still want to show the spinner during redirect\n setIsLoading(true);\n const iframeBody =\n iframeRef.current.contentWindow.document.body.innerHTML;\n\n // If we're doing a server token exchange, we need to call the server a second time\n // using a fetch so that we're on the same domain and cookies can be sent and read\n // The server will use the presence of the code_verifier cookie to determine whether to do a token exchange or not.\n // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,\n // and we'll do the exchange request from here, which will include the cookies.\n if (iframeBody.includes(TOKEN_EXCHANGE_TRIGGER_TEXT)) {\n const params = new URL(iframeUrl).searchParams;\n const appUrl = globalThis.window?.location?.origin;\n fetch(\n `${config.redirectUrl}?${params.toString()}&appUrl=${appUrl}`,\n );\n } else {\n // if we're doing token-exchange in the client, we can just set the authResponseUrl\n // to be handled by the auth provider\n // iframeRef.current.setAttribute(\"src\", \"\");\n setTokenExchangeUrl(iframeUrl);\n }\n\n if (closeOnRedirect) onClose?.();\n return true; // Successfully processed the URL\n }\n } catch (e) {\n console.log(\"Waiting for redirect...\", e);\n }\n }\n return false; // Haven't processed the URL yet\n }, [closeOnRedirect, config, iframeRef, onClose]);\n\n const intervalId = useRef<NodeJS.Timeout>();\n\n const handleEscape = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose?.();\n }\n },\n [onClose],\n );\n\n // handle Escape\n useEffect(() => {\n window.addEventListener(\"keydown\", handleEscape);\n\n return () => window.removeEventListener(\"keydown\", handleEscape);\n });\n\n const handleIframeLoad = useCallback(() => {\n setIsLoading(false);\n\n const iframeHasUrl = processIframeUrl();\n\n if (iframeHasUrl && intervalId.current) {\n clearInterval(intervalId.current);\n }\n }, [processIframeUrl, setIsLoading, intervalId]);\n\n // if we're already authenticated then we're waiting either for the iframe to be closed\n // or the page to redirect, so we want to show the loading icon\n const showLoadingIcon = session?.authenticated || isLoading || isAuthLoading;\n\n const WrapperComponent = iframeMode === \"embedded\" ? NoChrome : IframeChrome;\n\n return (\n <WrapperComponent onClose={onClose}>\n {showLoadingIcon ? (\n <div\n id=\"civic-auth-loading-icon-wrapper\"\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"white\",\n }}\n >\n <LoadingIcon />\n </div>\n ) : null}\n\n <CivicAuthIframe\n ref={iframeRef}\n id={\"civic-auth-iframe\"}\n onLoad={handleIframeLoad}\n />\n </WrapperComponent>\n );\n};\n\nexport type { CivicAuthIframeContainerProps };\n\nexport { CivicAuthIframeContainer };\n"]}
|
|
1
|
+
{"version":3,"file":"CivicAuthIframeContainer.js","sourceRoot":"","sources":["../../../../src/shared/components/CivicAuthIframeContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { CloseIcon } from \"@/shared/components/CloseIcon.js\";\nimport { CivicAuthIframe } from \"@/shared/components/CivicAuthIframe.js\";\nimport { useIframe } from \"@/shared/hooks/index.js\";\nimport { TOKEN_EXCHANGE_TRIGGER_TEXT } from \"@/constants.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/index.js\";\nimport { useClientTokenExchangeSession } from \"@/shared/hooks/index.js\";\nimport { useSession } from \"@/shared/hooks/index.js\";\n\ntype CivicAuthIframeContainerProps = {\n onClose?: () => void;\n closeOnRedirect?: boolean;\n};\n\nfunction NoChrome({\n children,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return <div style={{ position: \"relative\" }}>{children}</div>;\n}\n\nexport function IframeChrome({\n children,\n onClose,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n const { setIframeAborted } = useIframe();\n return (\n <div\n style={{\n position: \"fixed\", // Change to fixed to stay in viewport\n left: 0,\n top: 0,\n zIndex: 50,\n display: \"flex\",\n height: \"100vh\",\n width: \"100vw\",\n minWidth: \"18rem\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(17, 24, 39, 0.5)\", // Semi-transparent dark background\n backdropFilter: \"blur(4px)\", // Optional: adds slight blur to background\n }}\n onClick={onClose}\n >\n <div\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n borderRadius: \"1.5rem\",\n backgroundColor: \"white\",\n padding: \"1.5rem\",\n boxShadow:\n \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n style={{\n position: \"absolute\",\n right: \"1rem\",\n top: \"1rem\",\n display: \"flex\",\n cursor: \"pointer\",\n alignItems: \"center\",\n justifyContent: \"center\",\n border: \"none\",\n backgroundColor: \"transparent\",\n padding: \"0.25rem\",\n color: \"#9ca3af\",\n }}\n onClick={() => {\n setIframeAborted(true);\n onClose?.();\n }}\n >\n <CloseIcon />\n </button>\n\n {children}\n </div>\n </div>\n );\n}\n\nconst CivicAuthIframeContainer = ({\n onClose,\n closeOnRedirect = true,\n}: CivicAuthIframeContainerProps) => {\n const [isLoading, setIsLoading] = useState(true);\n const { isLoading: isAuthLoading, data: session } = useSession();\n const config = useCivicAuthConfig();\n const [tokenExchangeUrl, setTokenExchangeUrl] = useState<string | null>(null);\n const { doTokenExchange } = useClientTokenExchangeSession();\n const { iframeRef, iframeMode } = useIframe();\n\n useEffect(() => {\n if (tokenExchangeUrl) {\n doTokenExchange?.(tokenExchangeUrl);\n }\n }, [doTokenExchange, tokenExchangeUrl]);\n\n const processIframeUrl = useCallback(() => {\n if (!config) return;\n if (iframeRef && iframeRef.current && iframeRef.current.contentWindow) {\n try {\n const iframeUrl = iframeRef.current.contentWindow.location.href;\n // we know that oauth has finished when the iframe redirects to our redirectUrl\n if (iframeUrl.startsWith(config.redirectUrl)) {\n // we still want to show the spinner during redirect\n setIsLoading(true);\n const iframeBody =\n iframeRef.current.contentWindow.document.body.innerHTML;\n\n // If we're doing a server token exchange, we need to call the server a second time\n // using a fetch so that we're on the same domain and cookies can be sent and read\n // The server will use the presence of the code_verifier cookie to determine whether to do a token exchange or not.\n // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,\n // and we'll do the exchange request from here, which will include the cookies.\n if (iframeBody.includes(TOKEN_EXCHANGE_TRIGGER_TEXT)) {\n const params = new URL(iframeUrl).searchParams;\n const appUrl = globalThis.window?.location?.origin;\n fetch(\n `${config.redirectUrl}?${params.toString()}&appUrl=${appUrl}`,\n );\n } else {\n // if we're doing token-exchange in the client, we can just set the authResponseUrl\n // to be handled by the auth provider\n // iframeRef.current.setAttribute(\"src\", \"\");\n setTokenExchangeUrl(iframeUrl);\n }\n\n if (closeOnRedirect) onClose?.();\n return true; // Successfully processed the URL\n }\n } catch {\n // ignore errors while waiting for redirect\n }\n }\n return false; // Haven't processed the URL yet\n }, [closeOnRedirect, config, iframeRef, onClose]);\n\n const intervalId = useRef<NodeJS.Timeout>();\n\n const handleEscape = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose?.();\n }\n },\n [onClose],\n );\n\n // handle Escape\n useEffect(() => {\n window.addEventListener(\"keydown\", handleEscape);\n\n return () => window.removeEventListener(\"keydown\", handleEscape);\n });\n\n const handleIframeLoad = useCallback(() => {\n setIsLoading(false);\n\n const iframeHasUrl = processIframeUrl();\n\n if (iframeHasUrl && intervalId.current) {\n clearInterval(intervalId.current);\n }\n }, [processIframeUrl, setIsLoading, intervalId]);\n\n // if we're already authenticated then we're waiting either for the iframe to be closed\n // or the page to redirect, so we want to show the loading icon\n const showLoadingIcon = session?.authenticated || isLoading || isAuthLoading;\n\n const WrapperComponent = iframeMode === \"embedded\" ? NoChrome : IframeChrome;\n\n return (\n <WrapperComponent onClose={onClose}>\n {showLoadingIcon ? (\n <div\n id=\"civic-auth-loading-icon-wrapper\"\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"white\",\n }}\n >\n <LoadingIcon />\n </div>\n ) : null}\n\n <CivicAuthIframe\n ref={iframeRef}\n id={\"civic-auth-iframe\"}\n onLoad={handleIframeLoad}\n />\n </WrapperComponent>\n );\n};\n\nexport type { CivicAuthIframeContainerProps };\n\nexport { CivicAuthIframeContainer };\n"]}
|
|
@@ -70,7 +70,7 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode, }) => {
|
|
|
70
70
|
const useIframeRef = iframeRef?.current || null;
|
|
71
71
|
await authInitiator.signIn(useIframeRef).catch((error) => {
|
|
72
72
|
setAuthStatus(types_js_1.AuthStatus.ERROR);
|
|
73
|
-
console.
|
|
73
|
+
console.error("signIn error", {
|
|
74
74
|
error,
|
|
75
75
|
isPopupError: error instanceof types_js_2.PopupError,
|
|
76
76
|
});
|
|
@@ -97,7 +97,7 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode, }) => {
|
|
|
97
97
|
const useIframeRef = logoutIframeRef?.current || null;
|
|
98
98
|
await authInitiator.signOut(idToken, useIframeRef).catch((error) => {
|
|
99
99
|
setAuthStatus(types_js_1.AuthStatus.ERROR);
|
|
100
|
-
console.
|
|
100
|
+
console.error("signOut error", {
|
|
101
101
|
error,
|
|
102
102
|
isPopupError: error instanceof types_js_2.PopupError,
|
|
103
103
|
});
|