diff --git a/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequest.ts b/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequest.ts index d57361c5614..a757e1ab771 100644 --- a/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequest.ts +++ b/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequest.ts @@ -57,7 +57,6 @@ export const handleSignInCallbackRequest: HandleSignInCallbackRequest = async ({ const { [PKCE_COOKIE_NAME]: clientPkce, [STATE_COOKIE_NAME]: clientState } = getCookieValuesFromRequest(request, [PKCE_COOKIE_NAME, STATE_COOKIE_NAME]); - // The state and pkce cookies are removed from cookie store after 5 minutes if (!clientState || !clientPkce) { const searchParamsString = createErrorSearchParamsString({ error: SIGN_IN_TIMEOUT_ERROR_CODE, @@ -72,7 +71,6 @@ export const handleSignInCallbackRequest: HandleSignInCallbackRequest = async ({ }); } - // Most likely the cookie has been tampered if (clientState !== state) { return new Response(null, { status: 400 }); } @@ -104,18 +102,21 @@ export const handleSignInCallbackRequest: HandleSignInCallbackRequest = async ({ createAuthFlowProofCookiesRemoveOptions(setCookieOptions), ); - // When Cognito redirects back to `/sign-in-callback`, the referer is Cognito - // endpoint. If redirect end user to `redirectOnSignInComplete` from this point, - // the referer remains the same. - // When authN token cookies set as `sameSite: 'strict'`, this may cause the - // authN tokens cookies set with the redirect response not to be sent to the - // server. Hence, sending a html page with status 200 to the client, and perform - // the redirection on the client side. + const url = new URL(request.url); + const redirectToParam = url.searchParams.get('redirectTo'); + + const safeRedirectTo = + redirectToParam && redirectToParam.startsWith('/') ? redirectToParam : null; + + const finalRedirect = + safeRedirectTo ?? + getRedirectOrDefault(handlerInput.redirectOnSignInComplete); + headers.set('Content-Type', 'text/html'); return new Response( createRedirectionIntermediary({ - redirectTo: getRedirectOrDefault(handlerInput.redirectOnSignInComplete), + redirectTo: finalRedirect, }), { status: 200, diff --git a/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequestForPagesRouter.ts b/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequestForPagesRouter.ts index 53c698e5e07..15cb68f35b2 100644 --- a/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequestForPagesRouter.ts +++ b/packages/adapter-nextjs/src/auth/handlers/handleSignInCallbackRequestForPagesRouter.ts @@ -63,7 +63,6 @@ export const handleSignInCallbackRequestForPagesRouter: HandleSignInCallbackRequ STATE_COOKIE_NAME, ]); - // The state and pkce cookies are removed from cookie store after 5 minutes if (!clientState || !clientPkce) { const searchParamsString = createErrorSearchParamsString({ error: SIGN_IN_TIMEOUT_ERROR_CODE, @@ -77,7 +76,6 @@ export const handleSignInCallbackRequestForPagesRouter: HandleSignInCallbackRequ return; } - // Most likely the cookie has been tampered if (clientState !== state) { response.status(400).end(); @@ -112,21 +110,24 @@ export const handleSignInCallbackRequestForPagesRouter: HandleSignInCallbackRequ createAuthFlowProofCookiesRemoveOptions(setCookieOptions), ); - // When Cognito redirects back to `/sign-in-callback`, the referer is Cognito - // endpoint. If redirect end user to `redirectOnSignInComplete` from this point, - // the referer remains the same. - // When authN token cookies set as `sameSite: 'strict'`, this may cause the - // authN tokens cookies set with the redirect response not to be sent to the - // server. Hence, sending a html page with status 200 to the client, and perform - // the redirection on the client side. + const url = new URL(request.url!); + const redirectToParam = url.searchParams.get('redirectTo'); + + const safeRedirectTo = + redirectToParam && redirectToParam.startsWith('/') + ? redirectToParam + : null; + + const finalRedirect = + safeRedirectTo ?? + getRedirectOrDefault(handlerInput.redirectOnSignInComplete); + response .appendHeader('Content-Type', 'text/html') .status(200) .send( createRedirectionIntermediary({ - redirectTo: getRedirectOrDefault( - handlerInput.redirectOnSignInComplete, - ), + redirectTo: finalRedirect, }), ); }; diff --git a/packages/core/package.json b/packages/core/package.json index 35698e57217..aec031b855d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -25,7 +25,7 @@ "build": "npm run clean && npm run generate-version && npm run build:esm-cjs && npm run build:umd", "generate-version": "genversion src/Platform/version.ts --es6 --semi --source ../aws-amplify", "clean": "npm run clean:size && rimraf dist lib lib-esm", - "clean:size": "rimraf dual-publish-tmp tmp*", + "clean:size": "rimraf dual-publish-tmp tmp", "format": "echo \"Not implemented\"", "lint": "eslint '**/*.{ts,tsx}' && npm run ts-coverage", "lint:fix": "eslint '**/*.{ts,tsx}' --fix",