@@ -10,7 +10,9 @@ import {
1010} from '@ac/constants/routes' ;
1111
1212export const accountCenterBasePath = '/account' ;
13- const storageKey = 'account-center-route-cache' ;
13+ const routeStorageKey = 'account-center-route-cache' ;
14+ const redirectStorageKey = 'logto:account-center:redirect-url' ;
15+ const redirectUrlParameter = 'redirect' ;
1416
1517const knownRoutePrefixes : readonly string [ ] = [
1618 emailRoute ,
@@ -41,25 +43,86 @@ const shouldSkipHandling = (search: string) => {
4143 return parameters . has ( 'code' ) || parameters . has ( 'error' ) ;
4244} ;
4345
46+ /**
47+ * Get the stored redirect URL from sessionStorage.
48+ */
49+ export const getRedirectUrl = ( ) : string | undefined => {
50+ if ( typeof window === 'undefined' ) {
51+ return ;
52+ }
53+
54+ return sessionStorage . getItem ( redirectStorageKey ) ?? undefined ;
55+ } ;
56+
57+ /**
58+ * Store the redirect URL to sessionStorage.
59+ * The URL is validated to be a valid absolute URL with http/https protocol.
60+ */
61+ export const setRedirectUrl = ( url : string ) : boolean => {
62+ if ( typeof window === 'undefined' ) {
63+ return false ;
64+ }
65+
66+ try {
67+ const parsed = new URL ( url ) ;
68+ // Only allow http and https protocols
69+ if ( parsed . protocol !== 'http:' && parsed . protocol !== 'https:' ) {
70+ return false ;
71+ }
72+ sessionStorage . setItem ( redirectStorageKey , url ) ;
73+ return true ;
74+ } catch {
75+ // Invalid URL
76+ return false ;
77+ }
78+ } ;
79+
80+ /**
81+ * Clear the stored redirect URL from sessionStorage.
82+ */
83+ export const clearRedirectUrl = ( ) : void => {
84+ if ( typeof window === 'undefined' ) {
85+ return ;
86+ }
87+
88+ sessionStorage . removeItem ( redirectStorageKey ) ;
89+ } ;
90+
91+ /**
92+ * Parse and store the redirect URL from the query parameter.
93+ * This needs to be done before OAuth flow starts so it persists through the sign-in.
94+ */
95+ const handleRedirectParameter = ( ) => {
96+ const parameters = new URLSearchParams ( window . location . search ) ;
97+ const redirectUrl = parameters . get ( redirectUrlParameter ) ;
98+
99+ if ( redirectUrl ) {
100+ setRedirectUrl ( redirectUrl ) ;
101+ }
102+ } ;
103+
44104/**
45105 * Handle Account Center route restoration for sign in redirect.
46106 */
47107export const handleAccountCenterRoute = ( ) => {
108+ // Parse and store redirect URL first (before any OAuth redirects)
109+ handleRedirectParameter ( ) ;
110+
48111 if ( shouldSkipHandling ( window . location . search ) ) {
49112 return ;
50113 }
51114
52115 // Restore the stored route if the current path is the base path.
53116 if ( window . location . pathname === accountCenterBasePath ) {
54- const storedRoute = parseStoredRoute ( sessionStorage . getItem ( storageKey ) ?? undefined ) ;
117+ const storedRoute = parseStoredRoute ( sessionStorage . getItem ( routeStorageKey ) ?? undefined ) ;
55118 if ( ! storedRoute ) {
56- sessionStorage . removeItem ( storageKey ) ;
119+ sessionStorage . removeItem ( routeStorageKey ) ;
57120 return ;
58121 }
59122
60123 const { search, hash } = window . location ;
61124 window . history . replaceState ( { } , '' , `${ storedRoute } ${ search } ${ hash } ` ) ;
62125 } else if ( isKnownRoute ( window . location . pathname ) ) {
63- sessionStorage . setItem ( storageKey , window . location . pathname ) ;
126+ sessionStorage . setItem ( routeStorageKey , window . location . pathname ) ;
64127 }
65128} ;
0 commit comments