@@ -28,6 +28,15 @@ export const LoginPage: FC = () => {
2828const navigate = useNavigate ( ) ;
2929const { metadata} = useEmbeddedMetadata ( ) ;
3030const buildInfoQuery = useQuery ( buildInfo ( metadata [ "build-info" ] ) ) ;
31+ let redirectError :Error | null = null ;
32+ let redirectUrl :URL | null = null ;
33+ try {
34+ redirectUrl = new URL ( redirectTo ) ;
35+ } catch {
36+ // Do nothing
37+ }
38+
39+ const isApiRouteRedirect = redirectTo . startsWith ( "/api/v2" ) ;
3140
3241useEffect ( ( ) => {
3342if ( ! buildInfoQuery . data || isSignedIn ) {
@@ -42,41 +51,24 @@ export const LoginPage: FC = () => {
4251} , [ isSignedIn , buildInfoQuery . data , user ?. id ] ) ;
4352
4453if ( isSignedIn ) {
45- if ( buildInfoQuery . data ) {
46- // This uses `navigator.sendBeacon`, so window.href
47- // will not stop the request from being sent!
48- sendDeploymentEvent ( buildInfoQuery . data , {
49- type :"deployment_login" ,
50- user_id :user ?. id ,
51- } ) ;
54+ // The reason we need `window.location.href` for api redirects is that
55+ // we need the page to reload and make a request to the backend. If we
56+ // use `<Navigate>`, react would handle the redirect itself and never
57+ // request the page from the backend.
58+ if ( isApiRouteRedirect ) {
59+ const sanitizedUrl = new URL ( redirectTo , window . location . origin ) ;
60+ window . location . href = sanitizedUrl . pathname + sanitizedUrl . search ;
61+ // Setting the href should immediately request a new page. Show an
62+ // error state if it doesn't.
63+ redirectError = new Error ( "unable to redirect" ) ;
64+ } else {
65+ return (
66+ < Navigate
67+ to = { redirectUrl ?redirectUrl . pathname :redirectTo }
68+ replace
69+ />
70+ ) ;
5271}
53-
54- // If the redirect is going to a workspace application, and we
55- // are missing authentication, then we need to change the href location
56- // to trigger a HTTP request. This allows the BE to generate the auth
57- // cookie required. Similarly for the OAuth2 exchange as the authorization
58- // page is served by the backend.
59- // If no redirect is present, then ignore this branched logic.
60- if ( redirectTo !== "" && redirectTo !== "/" ) {
61- try {
62- // This catches any absolute redirects. Relative redirects
63- // will fail the try/catch. Subdomain apps are absolute redirects.
64- const redirectURL = new URL ( redirectTo ) ;
65- if ( redirectURL . host !== window . location . host ) {
66- window . location . href = redirectTo ;
67- return null ;
68- }
69- } catch {
70- // Do nothing
71- }
72- // Path based apps and OAuth2.
73- if ( redirectTo . includes ( "/apps/" ) || redirectTo . includes ( "/oauth2/" ) ) {
74- window . location . href = redirectTo ;
75- return null ;
76- }
77- }
78-
79- return < Navigate to = { redirectTo } replace /> ;
8072}
8173
8274if ( isConfiguringTheFirstUser ) {
@@ -90,14 +82,15 @@ export const LoginPage: FC = () => {
9082</ Helmet >
9183< LoginPageView
9284authMethods = { authMethodsQuery . data }
93- error = { signInError }
85+ error = { signInError ?? redirectError }
9486isLoading = { isLoading || authMethodsQuery . isLoading }
9587buildInfo = { buildInfoQuery . data }
9688isSigningIn = { isSigningIn }
9789onSignIn = { async ( { email, password} ) => {
9890await signIn ( email , password ) ;
9991navigate ( "/" ) ;
10092} }
93+ redirectTo = { redirectTo }
10194/>
10295</ >
10396) ;