@@ -107,6 +107,17 @@ <h1>✅ Authentication Successful!</h1>
107107 < script >
108108 ( function ( ) {
109109 try {
110+ // Prevent duplicate execution on mobile (when switching back to browser)
111+ const redirectKey = 'atmosphere_oauth_redirected' ;
112+ if ( sessionStorage . getItem ( redirectKey ) === 'true' ) {
113+ // Already redirected, show completion message
114+ document . querySelector ( '.spinner' ) . style . display = 'none' ;
115+ document . querySelector ( 'h1' ) . textContent = '✅ Redirected!' ;
116+ document . getElementById ( 'status' ) . textContent = 'Return to Obsidian to complete login.' ;
117+ document . getElementById ( 'manual-link' ) . classList . add ( 'show' ) ;
118+ return ;
119+ }
120+
110121 // extract OAuth parameters from URL hash (not search string)
111122 const params = new URLSearchParams ( window . location . hash . slice ( 1 ) ) ;
112123
@@ -115,7 +126,14 @@ <h1>✅ Authentication Successful!</h1>
115126 // store the URI for manual copy
116127 document . getElementById ( 'link-text' ) . textContent = obsidianUri ;
117128
118- window . location . href = obsidianUri ;
129+ // Mark as redirected BEFORE the redirect to prevent race conditions
130+ sessionStorage . setItem ( redirectKey , 'true' ) ;
131+
132+ // Small delay to ensure any pending IndexedDB writes complete
133+ // This is important on mobile where the browser may suspend the tab
134+ setTimeout ( function ( ) {
135+ window . location . href = obsidianUri ;
136+ } , 100 ) ;
119137
120138 setTimeout ( function ( ) {
121139 const spinner = document . querySelector ( '.spinner' ) ;
0 commit comments