From d94091ae4e1d16bd59fe2b9e2b1fb8cdf7351dd3 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Thu, 30 Oct 2025 11:33:23 +0100 Subject: [PATCH] Add webviewGoogleSignin --- web/lib/firebase/users.ts | 70 +++++++++++++++++++++++++++++++-------- web/pages/_app.tsx | 29 ++++++++++++++++ 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/web/lib/firebase/users.ts b/web/lib/firebase/users.ts index 84cc69f..5a5c52f 100644 --- a/web/lib/firebase/users.ts +++ b/web/lib/firebase/users.ts @@ -43,15 +43,58 @@ export function writeReferralInfo( } } -// export function isAndroidWebView() { -// try { -// // Detect if Android bridge exists -// return typeof (window as any).AndroidBridge?.isNativeApp === 'function'; -// } catch { -// return false; -// } -// } +export function isAndroidWebView() { + try { + // Detect if Android bridge exists + return typeof (window as any).AndroidBridge?.isNativeApp === 'function'; + } catch { + return false; + } +} +async function generatePKCE() { + const array = new Uint8Array(32); + crypto.getRandomValues(array); + const codeVerifier = btoa(String.fromCharCode(...array)) + .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + + const encoder = new TextEncoder(); + const hashBuffer = await crypto.subtle.digest('SHA-256', encoder.encode(codeVerifier)); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + const codeChallenge = btoa(String.fromCharCode(...hashArray)) + .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + + console.log({codeVerifier, codeChallenge}) + return {codeVerifier, codeChallenge}; +} + +export const GOOGLE_CLIENT_ID = '253367029065-khkj31qt22l0vc3v754h09vhpg6t33ad.apps.googleusercontent.com' + +/** + * Authenticates a Firebase client running a webview APK on Android with Google OAuth. + * + * `https://accounts.google.com/o/oauth2/v2/auth?${params}` to get the code (in external browser, as google blocks it in webview) + * Redirects to `com.compassmeet:/auth` (in webview java main activity) + * 'https://oauth2.googleapis.com/token' to get the ID token (in javascript app) + * signInWithCredential(auth, credential) to set up firebase user in client (auth.currentUser) + * + * @public + */ +export async function webviewGoogleSignin() { + const {codeVerifier, codeChallenge} = await generatePKCE(); + localStorage.setItem('pkce_verifier', codeVerifier); + + const params = new URLSearchParams({ + client_id: GOOGLE_CLIENT_ID, + redirect_uri: 'com.compassmeet:/auth', // your deep link + response_type: 'code', + scope: 'openid email profile', + code_challenge: codeChallenge, + code_challenge_method: 'S256', + }); + + window.open(`https://accounts.google.com/o/oauth2/v2/auth?${params}`, '_system'); +} // export async function googleNativeLogin() { // console.log('Platform:', Capacitor.getPlatform()) @@ -94,12 +137,11 @@ export function writeReferralInfo( // export const isRunningInAPK = () => typeof window !== 'undefined' && (window as any).IS_APK === true export async function firebaseLogin() { - // if (isAndroidWebView()) { - // console.log('Running in APK') - // return await googleNativeLogin() - // return await signInWithRedirect(auth, new GoogleAuthProvider()) - // } - // console.log('Running in web') + if (isAndroidWebView()) { + console.log('Running in APK') + return await webviewGoogleSignin() + } + console.log('Running in web') const provider = new GoogleAuthProvider() return signInWithPopup(auth, provider).then(async (result) => { return result diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index 33f7bc4..043f5d7 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -12,6 +12,7 @@ import clsx from 'clsx' import {initTracking} from 'web/lib/service/analytics' import WebPush from "web/lib/service/web-push"; import AndroidPush from "web/lib/service/android-push"; +import {GOOGLE_CLIENT_ID} from "web/lib/firebase/users"; // See https://nextjs.org/docs/basic-features/font-optimization#google-fonts // and if you add a font, you must add it to tailwind config as well for it to work. @@ -63,6 +64,34 @@ function MyApp({Component, pageProps}: AppProps) { } }, []) + window.addEventListener('oauthRedirect', async (event: any) => { + console.log('Received oauthRedirect event:', event.detail); + const url = new URL(event.detail); + + const code = url.searchParams.get('code'); + if (!code) { + console.error('No code found in URL'); + return; + } + + const codeVerifier = localStorage.getItem('pkce_verifier'); + + const tokenResponse = await fetch('https://oauth2.googleapis.com/token', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + client_id: GOOGLE_CLIENT_ID, + code, + code_verifier: codeVerifier!, + redirect_uri: 'com.compassmeet:/auth', + grant_type: 'authorization_code', + }), + }); + + const tokens = await tokenResponse.json(); + console.log('Tokens:', tokens); + }); + const title = 'Compass' const description = 'The platform for intentional connections'