| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <title>Signing inβ¦</title> |
| <style> |
| body { background: #0d0e11; color: #e8eaf0; font-family: system-ui, sans-serif; |
| display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; } |
| .box { text-align: center; } |
| .spinner { width: 32px; height: 32px; border: 3px solid rgba(229,200,70,0.2); |
| border-top-color: #e5c846; border-radius: 50%; animation: spin 0.8s linear infinite; |
| margin: 0 auto 16px; } |
| @keyframes spin { to { transform: rotate(360deg); } } |
| </style> |
| </head> |
| <body> |
| <div class="box"> |
| <div class="spinner"></div> |
| <p id="msg">Completing sign-inβ¦</p> |
| </div> |
| <script> |
| |
| function getTokens() { |
| const hash = new URLSearchParams(location.hash.replace('#', '')); |
| const search = new URLSearchParams(location.search); |
| return { |
| access_token: hash.get('access_token') || search.get('access_token'), |
| refresh_token: hash.get('refresh_token') || search.get('refresh_token'), |
| error: hash.get('error') || search.get('error'), |
| error_desc: hash.get('error_description') || search.get('error_description'), |
| }; |
| } |
| |
| const tokens = getTokens(); |
| const msgEl = document.getElementById('msg'); |
| |
| if (tokens.error) { |
| msgEl.textContent = 'Sign-in error: ' + (tokens.error_desc || tokens.error); |
| } else if (tokens.access_token) { |
| |
| |
| |
| const payload = JSON.stringify({ |
| access_token: tokens.access_token, |
| refresh_token: tokens.refresh_token || '', |
| }); |
| localStorage.setItem('ipai_oauth_pending', payload); |
| |
| |
| if (window.opener && !window.opener.closed) { |
| try { |
| window.opener.postMessage({ |
| type: 'oauth:callback', |
| access_token: tokens.access_token, |
| refresh_token: tokens.refresh_token, |
| }, location.origin); |
| } catch (_) { } |
| } |
| |
| msgEl.textContent = 'Sign-in complete! Closingβ¦'; |
| |
| setTimeout(() => { |
| try { window.close(); } catch (_) { } |
| }, 300); |
| } else { |
| msgEl.textContent = 'No token received. You can close this window.'; |
| } |
| </script> |
| |
| <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> |
| <div id="turnstile-overlay" style="position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.6);z-index:9999;"> |
| <div style="background:#0d0e11;padding:18px;border-radius:10px;text-align:center;max-width:420px;width:90%;"> |
| <div style="color:#d7d7d7;margin-bottom:12px;">Please verify you are human to continue.</div> |
| <div class="cf-turnstile" data-sitekey="0x4AAAAAAC1ZXKIhZ9Kdz8j9" data-callback="onTurnstileSuccess"></div> |
| </div> |
| </div> |
| <script type="module" src="/js/turnstile.js"></script> |
| </body> |
| </html> |