@@ -89,16 +89,6 @@ function generateCodeVerifier() {
8989 return result ;
9090}
9191
92- function generateCodeChallenge ( verifier ) {
93- return crypto . subtle . digest ( 'SHA-256' , new TextEncoder ( ) . encode ( verifier ) )
94- . then ( arrayBuffer => {
95- const base64Url = btoa ( String . fromCharCode ( ...new Uint8Array ( arrayBuffer ) ) )
96- . replace ( / = / g, '' )
97- . replace ( / \+ / g, '-' )
98- . replace ( / \/ / g, '_' ) ;
99- return base64Url ;
100- } ) ;
101- }
10292
10393function TestIframe ( ) {
10494 const sdk = useDescope ( ) ;
@@ -107,131 +97,88 @@ function TestIframe() {
10797 const silentAuthCheckedRef = useRef ( false ) ;
10898 const [ silentAuthStatus , setSilentAuthStatus ] = useState ( null ) ;
10999
110- // Silent authentication check using iframe for OIDC federation
111100 useEffect ( ( ) => {
112- const checkSilentAuth = async ( ) => {
113- try {
114- console . log ( 'Starting silent authentication check with iframe...' ) ;
115-
116- const codeVerifier = generateCodeVerifier ( ) ;
117- const codeChallenge = await generateCodeChallenge ( codeVerifier ) ;
118- const state = generateCodeVerifier ( ) ;
119- sessionStorage . setItem ( 'silent-auth-verifier' , codeVerifier ) ;
120- sessionStorage . setItem ( 'silent-auth-state' , state ) ;
121-
122- // Set up message listener for iframe response BEFORE creating iframe
123- const messageHandler = async ( event ) => {
124- console . log ( 'Message received:' , event . data , 'from origin:' , event . origin ) ;
101+ if ( isSessionLoading ) return ;
125102
126- if ( event . origin !== window . location . origin ) {
127- console . log ( 'Ignoring message from different origin' ) ;
128- return ;
129- }
103+ if ( isAuthenticated ) {
104+ silentAuthCheckedRef . current = true ;
105+ setSilentAuthChecked ( true ) ;
106+ setSilentAuthStatus ( 'User already authenticated' ) ;
107+ return ;
108+ }
130109
131- if ( event . data . type === 'silent-auth-result' ) {
132- console . log ( 'Silent auth result received:' , event . data ) ;
110+ if ( silentAuthCheckedRef . current ) return ;
133111
134- const expectedState = sessionStorage . getItem ( 'silent-auth-state' ) ;
135- sessionStorage . removeItem ( 'silent-auth-state' ) ;
136- if ( event . data . state !== expectedState ) {
137- console . log ( 'State mismatch — ignoring response' ) ;
138- return ;
139- }
112+ const checkSilentAuth = async ( ) => {
113+ const state = generateCodeVerifier ( ) ;
114+ sessionStorage . setItem ( 'silent-auth-state' , state ) ;
115+
116+ const done = ( status ) => {
117+ const iframe = document . getElementById ( 'silent-auth-iframe' ) ;
118+ if ( iframe && iframe . parentNode ) document . body . removeChild ( iframe ) ;
119+ window . removeEventListener ( 'message' , messageHandler ) ;
120+ silentAuthCheckedRef . current = true ;
121+ setSilentAuthStatus ( status ) ;
122+ setSilentAuthChecked ( true ) ;
123+ } ;
140124
141- // Clean up
142- const iframe = document . getElementById ( 'silent-auth-iframe' ) ;
143- if ( iframe && iframe . parentNode ) {
144- document . body . removeChild ( iframe ) ;
145- }
146- window . removeEventListener ( 'message' , messageHandler ) ;
147- silentAuthCheckedRef . current = true ;
125+ const messageHandler = async ( event ) => {
126+ if ( event . origin !== window . location . origin ) return ;
127+ if ( event . data . type !== 'silent-auth-result' ) return ;
128+
129+ const expectedState = sessionStorage . getItem ( 'silent-auth-state' ) ;
130+ sessionStorage . removeItem ( 'silent-auth-state' ) ;
131+ if ( event . data . state !== expectedState ) {
132+ console . log ( 'Silent auth: state mismatch, ignoring' ) ;
133+ return ;
134+ }
135+
136+ if ( event . data . code ) {
137+ try {
138+ await sdk . oauth . exchange ( event . data . code ) ;
139+ done ( 'Authenticated via custom domain' ) ;
140+ } catch ( err ) {
141+ console . log ( 'Silent auth: exchange failed' , err ) ;
142+ done ( 'No existing session' ) ;
143+ }
144+ } else {
145+ done ( 'No existing session' ) ;
146+ }
147+ } ;
148148
149- if ( event . data . code ) {
150- // Exchange code for token using Descope SDK
151- try {
152- console . log ( 'Exchanging code for token...' ) ;
153- const storedVerifier = sessionStorage . getItem ( 'silent-auth-verifier' ) ;
154- sessionStorage . removeItem ( 'silent-auth-verifier' ) ;
155- await sdk . oauth . exchange ( event . data . code , storedVerifier ) ;
156- setSilentAuthStatus ( 'User authenticated via custom domain' ) ;
157- console . log ( 'Silent auth successful - user is logged in' ) ;
158- } catch ( error ) {
159- console . log ( 'Failed to exchange code:' , error ) ;
160- setSilentAuthStatus ( 'No existing session found' ) ;
161- }
162- } else if ( event . data . error ) {
163- console . log ( 'Silent auth returned error:' , event . data . error ) ;
164- setSilentAuthStatus ( 'No existing session found' ) ;
165- }
149+ window . addEventListener ( 'message' , messageHandler ) ;
166150
167- silentAuthCheckedRef . current = true ;
168- setSilentAuthChecked ( true ) ;
169- }
170- } ;
151+ const iframe = document . createElement ( 'iframe' ) ;
152+ iframe . style . display = 'none' ;
153+ iframe . id = 'silent-auth-iframe' ;
171154
172- window . addEventListener ( 'message' , messageHandler ) ;
173- console . log ( 'Message listener added' ) ;
155+ const projectId = 'Puse136yK1TiyR4tmmaVToRDQs9icEIl' ;
156+ const customDomain = 'https://auth.reuven.descope.org' ;
157+ const redirectUri = `${ window . location . origin } /silent-callback` ;
174158
175- // Create hidden iframe for silent auth
176- const iframe = document . createElement ( 'iframe' ) ;
177- iframe . style . display = 'none' ;
178- iframe . id = 'silent-auth-iframe' ;
159+ iframe . src = `${ customDomain } /oauth2/v1/authorize?` +
160+ `response_type=code` +
161+ `&client_id=${ projectId } ` +
162+ `&redirect_uri=${ encodeURIComponent ( redirectUri ) } ` +
163+ `&oidc_error_redirect_uri=${ encodeURIComponent ( redirectUri ) } ` +
164+ `&state=${ state } ` +
165+ `&prompt=none` +
166+ `&scope=openid profile email` ;
179167
180- const projectId = 'Puse136yK1TiyR4tmmaVToRDQs9icEIl' ;
181- const customDomain = 'https://auth.reuven.descope.org' ;
182- const redirectUri = `${ window . location . origin } /silent-callback` ;
168+ document . body . appendChild ( iframe ) ;
183169
184- // Construct OIDC authorization URL with PKCE and prompt=none for silent auth
185- const authUrl = `${ customDomain } /oauth2/v1/authorize?` +
186- `response_type=code` +
187- `&client_id=${ projectId } ` +
188- `&redirect_uri=${ encodeURIComponent ( redirectUri ) } ` +
189- `&oidc_error_redirect_uri=${ encodeURIComponent ( redirectUri ) } ` +
190- `&state=${ state } ` +
191- `&code_challenge=${ codeChallenge } ` +
192- `&code_challenge_method=S256` +
193- `&prompt=none` +
194- `&scope=openid profile email` ;
195-
196- console . log ( 'Silent auth URL:' , authUrl ) ;
197-
198- // Set timeout in case iframe doesn't respond
199- setTimeout ( ( ) => {
200- if ( ! silentAuthCheckedRef . current ) {
201- console . log ( 'Silent auth timed out' ) ;
202- window . removeEventListener ( 'message' , messageHandler ) ;
203- const iframe = document . getElementById ( 'silent-auth-iframe' ) ;
204- if ( iframe && iframe . parentNode ) {
205- document . body . removeChild ( iframe ) ;
206- }
207- silentAuthCheckedRef . current = true ;
208- setSilentAuthStatus ( 'Silent auth timeout' ) ;
209- setSilentAuthChecked ( true ) ;
210- }
211- } , 10000 ) ;
212-
213- // Add iframe to page and start silent auth
214- document . body . appendChild ( iframe ) ;
215- console . log ( 'Iframe added to page, loading URL...' ) ;
216- iframe . src = authUrl ;
217-
218- } catch ( error ) {
219- console . error ( 'Silent auth error:' , error ) ;
220- setSilentAuthStatus ( 'Silent auth failed' ) ;
221- setSilentAuthChecked ( true ) ;
222- }
170+ setTimeout ( ( ) => {
171+ if ( ! silentAuthCheckedRef . current ) done ( 'Silent auth timeout' ) ;
172+ } , 10000 ) ;
223173 } ;
224174
225- // Only run silent auth check once on mount and if not already authenticated
226- if ( ! isSessionLoading && ! silentAuthChecked && ! isAuthenticated ) {
227- checkSilentAuth ( ) ;
228- } else if ( ! isSessionLoading && ( isAuthenticated || silentAuthChecked ) ) {
175+ checkSilentAuth ( ) . catch ( ( err ) => {
176+ console . error ( 'Silent auth error:' , err ) ;
177+ silentAuthCheckedRef . current = true ;
178+ setSilentAuthStatus ( 'Silent auth failed' ) ;
229179 setSilentAuthChecked ( true ) ;
230- if ( isAuthenticated ) {
231- setSilentAuthStatus ( 'User already authenticated' ) ;
232- }
233- }
234- } , [ sdk , isSessionLoading , silentAuthChecked , isAuthenticated ] ) ;
180+ } ) ;
181+ } , [ sdk , isSessionLoading , isAuthenticated ] ) ;
235182
236183 const runSSO = async ( ) => {
237184 const d = await sdk . saml . start ( 'descope.com' , 'http://localhost:3000' ) ;
0 commit comments