11import { type ActionFunction , type LoaderFunction , redirect , createCookie } from "@remix-run/node" ;
22import { authenticator } from "~/services/auth.server" ;
3+ import { env } from "~/env.server" ;
4+ import { sanitizeRedirectPath } from "~/utils" ;
35
46export let loader : LoaderFunction = ( ) => redirect ( "/login" ) ;
57
68export let action : ActionFunction = async ( { request } ) => {
79 const url = new URL ( request . url ) ;
810 const redirectTo = url . searchParams . get ( "redirectTo" ) ;
11+ const safeRedirect = sanitizeRedirectPath ( redirectTo , "/" ) ;
912
1013 try {
1114 // call authenticate as usual, in successRedirect use returnTo or a fallback
1215 return await authenticator . authenticate ( "google" , request , {
13- successRedirect : redirectTo ?? "/" ,
16+ successRedirect : safeRedirect ,
1417 failureRedirect : "/login" ,
1518 } ) ;
1619 } catch ( error ) {
@@ -19,8 +22,8 @@ export let action: ActionFunction = async ({ request }) => {
1922 // if the error is a Response and is a redirect
2023 if ( error instanceof Response ) {
2124 // we need to append a Set-Cookie header with a cookie storing the
22- // returnTo value
23- error . headers . append ( "Set-Cookie" , await redirectCookie . serialize ( redirectTo ) ) ;
25+ // returnTo value (store the sanitized path)
26+ error . headers . append ( "Set-Cookie" , await redirectCookie . serialize ( safeRedirect ) ) ;
2427 }
2528 throw error ;
2629 }
@@ -29,5 +32,7 @@ export let action: ActionFunction = async ({ request }) => {
2932export const redirectCookie = createCookie ( "google-redirect-to" , {
3033 maxAge : 60 * 60 , // 1 hour
3134 httpOnly : true ,
35+ sameSite : "lax" ,
36+ secure : env . NODE_ENV === "production" ,
3237} ) ;
3338
0 commit comments