diff --git a/backend/api/src/app.ts b/backend/api/src/app.ts index 61f112e..30c05a8 100644 --- a/backend/api/src/app.ts +++ b/backend/api/src/app.ts @@ -69,6 +69,7 @@ import {IS_LOCAL} from "common/envs/constants"; import {localSendTestEmail} from "api/test"; import path from "node:path"; import {saveSubscriptionMobile} from "api/save-subscription-mobile"; +import {authGoogle} from "api/auth-google"; // const corsOptions: CorsOptions = { // origin: ['*'], // Only allow requests from this domain @@ -358,6 +359,7 @@ const handlers: { [k in APIPath]: APIHandler } = { 'save-subscription-mobile': saveSubscriptionMobile, 'create-bookmarked-search': createBookmarkedSearch, 'delete-bookmarked-search': deleteBookmarkedSearch, + 'auth-google': authGoogle, } Object.entries(handlers).forEach(([path, handler]) => { diff --git a/backend/api/src/auth-google.ts b/backend/api/src/auth-google.ts new file mode 100644 index 0000000..c13831d --- /dev/null +++ b/backend/api/src/auth-google.ts @@ -0,0 +1,32 @@ +import {APIHandler} from './helpers/endpoint' +import {GOOGLE_CLIENT_ID} from "common/constants"; + +export const authGoogle: APIHandler<'auth-google'> = async ( + {code}, + _auth +) => { + console.log('Google Auth Code:', code) + if (!code) return {success: false, result: {}} + + const body = { + client_id: GOOGLE_CLIENT_ID, + client_secret: process.env.GOOGLE_CLIENT_SECRET!, + code: code as string, + grant_type: 'authorization_code', + redirect_uri: 'https://www.compassmeet.com/auth/callback', + }; + console.log('Body:', body) + const tokenRes = await fetch('https://oauth2.googleapis.com/token', { + method: 'POST', + headers: {'Content-Type': 'application/x-www-form-urlencoded'}, + body: new URLSearchParams(body), + }); + + const tokens = await tokenRes.json(); + console.log('Google Tokens:', tokens); + + return { + success: true, + result: {tokens}, + } +} diff --git a/common/src/api/schema.ts b/common/src/api/schema.ts index f3d8b8f..56ee573 100644 --- a/common/src/api/schema.ts +++ b/common/src/api/schema.ts @@ -733,6 +733,17 @@ export const API = (_apiTypeCheck = { summary: 'Delete a bookmarked search by ID', tag: 'Searches', }, + 'auth-google': { + method: 'GET', + authed: false, + rateLimited: true, + returns: {} as any, + props: z.object({ + code: z.string(), + }), + summary: 'Google Auth', + tag: 'Authentication', + }, } as const) export type APIPath = keyof typeof API diff --git a/common/src/constants.ts b/common/src/constants.ts index 424bdc8..b6afc27 100644 --- a/common/src/constants.ts +++ b/common/src/constants.ts @@ -24,3 +24,6 @@ export const IS_MAINTENANCE = false // set to true to enable the maintenance mod export const MIN_BIO_LENGTH = 250 +export const WEB_GOOGLE_CLIENT_ID = '253367029065-khkj31qt22l0vc3v754h09vhpg6t33ad.apps.googleusercontent.com' +export const ANDROID_GOOGLE_CLIENT_ID = '253367029065-s9sr5vqgkhc8f7p5s6ti6a4chqsrqgc4.apps.googleusercontent.com' +export const GOOGLE_CLIENT_ID = WEB_GOOGLE_CLIENT_ID diff --git a/common/src/secrets.ts b/common/src/secrets.ts index 62d263a..c3f6bdb 100644 --- a/common/src/secrets.ts +++ b/common/src/secrets.ts @@ -26,6 +26,7 @@ export const secrets = ( 'VAPID_PUBLIC_KEY', 'VAPID_PRIVATE_KEY', 'DB_ENC_MASTER_KEY_BASE64', + 'GOOGLE_CLIENT_SECRET', // Some typescript voodoo to keep the string literal types while being not readonly. ] as const ).concat() diff --git a/web/lib/firebase/users.ts b/web/lib/firebase/users.ts index e72c778..0b8dccb 100644 --- a/web/lib/firebase/users.ts +++ b/web/lib/firebase/users.ts @@ -6,6 +6,7 @@ import {getAuth, GoogleAuthProvider, signInWithPopup} from 'firebase/auth' import {safeLocalStorage} from '../util/local' import {app} from './init' import {IS_LOCAL, WEB_URL} from "common/envs/constants"; +import {GOOGLE_CLIENT_ID} from "common/constants"; dayjs.extend(utc) @@ -69,10 +70,6 @@ async function generatePKCE() { return {codeVerifier, codeChallenge}; } -export const WEB_GOOGLE_CLIENT_ID = '253367029065-khkj31qt22l0vc3v754h09vhpg6t33ad.apps.googleusercontent.com' -export const ANDROID_GOOGLE_CLIENT_ID = '253367029065-s9sr5vqgkhc8f7p5s6ti6a4chqsrqgc4.apps.googleusercontent.com' -export const GOOGLE_CLIENT_ID = WEB_GOOGLE_CLIENT_ID - /** * Authenticates a Firebase client running a webview APK on Android with Google OAuth. * @@ -88,7 +85,7 @@ export async function webviewGoogleSignin() { localStorage.setItem('pkce_verifier', codeVerifier); const params = new URLSearchParams({ - client_id: ANDROID_GOOGLE_CLIENT_ID, + client_id: GOOGLE_CLIENT_ID, redirect_uri: `${WEB_URL}/auth/callback`, response_type: 'code', scope: 'openid email profile', diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index 5b51983..c44d037 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -12,7 +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 {ANDROID_GOOGLE_CLIENT_ID} from "web/lib/firebase/users"; +import {unauthedApi} from "common/util/api"; // 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. @@ -81,24 +81,9 @@ function MyApp({Component, pageProps}: AppProps) { return; } - const codeVerifier = localStorage.getItem('pkce_verifier'); - - const body = { - client_id: ANDROID_GOOGLE_CLIENT_ID, - code, - code_verifier: codeVerifier!, - redirect_uri: 'com.compassmeet:/auth', - grant_type: 'authorization_code', - } - console.log('Body:', body); - const tokenResponse = await fetch('https://oauth2.googleapis.com/token', { - method: 'POST', - headers: {'Content-Type': 'application/x-www-form-urlencoded'}, - body: new URLSearchParams(body), - }); - - const tokens = await tokenResponse.json(); - console.log('Tokens:', tokens); + const {result} = await unauthedApi('auth-google', {code}) + console.log('/auth-google result', result); + // google sign in } // Expose globally for native bridge diff --git a/web/pages/auth/callback.tsx b/web/pages/auth/callback.tsx index d259a2e..50f16d8 100644 --- a/web/pages/auth/callback.tsx +++ b/web/pages/auth/callback.tsx @@ -1,21 +1,18 @@ import {useEffect} from "react"; -import {GOOGLE_CLIENT_ID} from "web/lib/firebase/users"; export default function GoogleAuthCallback() { useEffect(() => { async function fetchToken() { const params = new URLSearchParams(window.location.search); - console.log('/auth/callback code', params); + console.log('/auth/callback', params); const code = params.get('code'); - const state = params.get('state'); - console.log('/auth/callback code', code); + // const state = params.get('state'); if (code) { + console.log('/auth/callback code', code); // Send code back to the native app - const deepLink = `com.compassmeet://auth?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state || '')}`; - window.location.href = deepLink; + window.location.href = `com.compassmeet://auth?code=${encodeURIComponent(code)}}`; - // // const codeVerifier = localStorage.getItem('pkce_verifier'); // const body = new URLSearchParams({ // client_id: GOOGLE_CLIENT_ID,