@@ -28,6 +28,15 @@ export const LoginPage: FC = () => {
28
28
const navigate = useNavigate ( ) ;
29
29
const { metadata } = useEmbeddedMetadata ( ) ;
30
30
const 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" ) ;
31
40
32
41
useEffect ( ( ) => {
33
42
if ( ! buildInfoQuery . data || isSignedIn ) {
@@ -42,41 +51,24 @@ export const LoginPage: FC = () => {
42
51
} , [ isSignedIn , buildInfoQuery . data , user ?. id ] ) ;
43
52
44
53
if ( 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
+ ) ;
52
71
}
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 /> ;
80
72
}
81
73
82
74
if ( isConfiguringTheFirstUser ) {
@@ -90,14 +82,15 @@ export const LoginPage: FC = () => {
90
82
</ Helmet >
91
83
< LoginPageView
92
84
authMethods = { authMethodsQuery . data }
93
- error = { signInError }
85
+ error = { signInError ?? redirectError }
94
86
isLoading = { isLoading || authMethodsQuery . isLoading }
95
87
buildInfo = { buildInfoQuery . data }
96
88
isSigningIn = { isSigningIn }
97
89
onSignIn = { async ( { email, password } ) => {
98
90
await signIn ( email , password ) ;
99
91
navigate ( "/" ) ;
100
92
} }
93
+ redirectTo = { redirectTo }
101
94
/>
102
95
</ >
103
96
) ;
0 commit comments