diff --git a/server/src/index.ts b/server/src/index.ts index 2fd12b9..68e2b63 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -28,6 +28,31 @@ app.use(cors({ // Serve uploaded files app.use('/uploads', express.static(UPLOADS_DIR)); +// iOS Google OAuth initiator — opens in ASWebAuthenticationSession (Safari jar). +// This GET endpoint calls Better Auth's sign-in/social internally (server-to-server), +// then forwards the state cookie and redirects to Google — all within the same +// Safari session. This keeps the state cookie in the same jar that will receive +// the Google callback, avoiding the state_mismatch error. +app.get('/api/ios-google', async (req, res) => { + const callbackURL = (req.query.callbackURL as string) || `https://labwise.wahwa.com/api/ios-callback`; + try { + const baRes = await fetch(`http://localhost:${PORT}/api/auth/sign-in/social`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Origin': 'https://labwise.wahwa.com' }, + body: JSON.stringify({ provider: 'google', callbackURL }), + redirect: 'manual', + }); + // Forward the state cookie Better Auth set, then redirect to Google + const setCookie = baRes.headers.get('set-cookie'); + if (setCookie) res.setHeader('Set-Cookie', setCookie); + const body = await baRes.json() as { url?: string }; + if (!body.url) return res.status(500).send('No redirect URL from auth server'); + return res.redirect(body.url); + } catch (e) { + return res.status(500).send('Auth initiation failed'); + } +}); + // iOS OAuth callback — must be registered before the Better Auth wildcard // so Express matches this specific path first. // Better Auth completes the Google flow, sets the session cookie, then