From 179c36060cfd618c337db47747659b0047987305 Mon Sep 17 00:00:00 2001 From: IronTony Date: Fri, 13 Mar 2026 18:14:28 +0100 Subject: [PATCH 1/6] feat: add Google Sign-In module for React Auth - Introduced a new package that provides a Google Sign-In adapter for both web and React Native. - Implemented native modules for iOS and Android to handle Google Sign-In functionality. - Added configuration options for client IDs and token management. - Included a component for easy integration in applications. - Updated and to include the new package and its dependencies. This addition enhances the authentication capabilities of the library. --- packages/google-signin/README.md | 355 ++ packages/google-signin/android/build.gradle | 37 + .../googlesignin/GoogleSignInModule.kt | 170 + .../google-signin/expo-module.config.json | 9 + .../ios/GoogleSignInModule.swift | 164 + .../ios/react-auth-google.podspec | 20 + packages/google-signin/package.json | 60 + .../google-signin/react-auth-google.podspec | 20 + packages/google-signin/src/index.native.ts | 4 + packages/google-signin/src/index.ts | 3 + .../src/native/GoogleAuthClient.ts | 155 + .../src/native/GoogleSignInButton.tsx | 101 + .../src/native/GoogleSignInModule.ts | 43 + packages/google-signin/src/native/index.ts | 3 + packages/google-signin/src/types.ts | 61 + .../google-signin/src/web/GoogleAuthClient.ts | 110 + .../src/web/GoogleSignInButton.tsx | 75 + packages/google-signin/src/web/gsi.ts | 147 + packages/google-signin/src/web/index.ts | 2 + .../test/GoogleAuthClient.native.spec.ts | 179 + .../test/GoogleAuthClient.web.spec.ts | 167 + packages/google-signin/test/test-utils.ts | 47 + packages/google-signin/tsconfig.json | 24 + packages/google-signin/vitest.config.ts | 16 + pnpm-lock.yaml | 3913 ++++++++--------- pnpm-workspace.yaml | 1 + 26 files changed, 3811 insertions(+), 2075 deletions(-) create mode 100644 packages/google-signin/README.md create mode 100644 packages/google-signin/android/build.gradle create mode 100644 packages/google-signin/android/src/main/java/expo/modules/googlesignin/GoogleSignInModule.kt create mode 100644 packages/google-signin/expo-module.config.json create mode 100644 packages/google-signin/ios/GoogleSignInModule.swift create mode 100644 packages/google-signin/ios/react-auth-google.podspec create mode 100644 packages/google-signin/package.json create mode 100644 packages/google-signin/react-auth-google.podspec create mode 100644 packages/google-signin/src/index.native.ts create mode 100644 packages/google-signin/src/index.ts create mode 100644 packages/google-signin/src/native/GoogleAuthClient.ts create mode 100644 packages/google-signin/src/native/GoogleSignInButton.tsx create mode 100644 packages/google-signin/src/native/GoogleSignInModule.ts create mode 100644 packages/google-signin/src/native/index.ts create mode 100644 packages/google-signin/src/types.ts create mode 100644 packages/google-signin/src/web/GoogleAuthClient.ts create mode 100644 packages/google-signin/src/web/GoogleSignInButton.tsx create mode 100644 packages/google-signin/src/web/gsi.ts create mode 100644 packages/google-signin/src/web/index.ts create mode 100644 packages/google-signin/test/GoogleAuthClient.native.spec.ts create mode 100644 packages/google-signin/test/GoogleAuthClient.web.spec.ts create mode 100644 packages/google-signin/test/test-utils.ts create mode 100644 packages/google-signin/tsconfig.json create mode 100644 packages/google-signin/vitest.config.ts diff --git a/packages/google-signin/README.md b/packages/google-signin/README.md new file mode 100644 index 0000000..1a97146 --- /dev/null +++ b/packages/google-signin/README.md @@ -0,0 +1,355 @@ +# React Auth - Google Sign-In + +> Google Sign-In adapter for [@forward-software/react-auth](https://github.com/forwardsoftware/react-auth) - Web and React Native + +Self-contained Google Sign-In integration with no external auth wrapper dependencies. Provides a ready-made `AuthClient` implementation and a drop-in `GoogleSignInButton` for both platforms. + +--- + +## Install + +```sh +npm install @forward-software/react-auth @forward-software/react-auth-google +``` + +### Platform requirements + +**Web** - No additional dependencies. The package loads Google Identity Services (GSI) script automatically. + +**React Native / Expo** - Requires a development build (not compatible with Expo Go): + +- iOS: Add the `GoogleSignIn` CocoaPod (included automatically via autolinking) +- Android: Uses Android Credential Manager with Google Identity (included via `build.gradle`) +- Run `npx expo prebuild` or use EAS Build to compile native code + +--- + +## Quick Start + +### 1. Create the auth client + +The setup is identical on both platforms - the bundler automatically resolves the correct implementation. + +```ts +// auth.ts +import { createAuth } from '@forward-software/react-auth'; +import { GoogleAuthClient } from '@forward-software/react-auth-google'; + +const googleAuth = new GoogleAuthClient({ + clientId: 'YOUR_GOOGLE_CLIENT_ID', +}); + +export const { AuthProvider, authClient, useAuthClient } = createAuth(googleAuth); +``` + +### 2. Wrap your app with AuthProvider + +```tsx +// App.tsx +import { AuthProvider } from './auth'; + +function App() { + return ( + + + + ); +} +``` + +### 3. Add the sign-in button + +```tsx +import { GoogleSignInButton } from '@forward-software/react-auth-google'; +import { useAuthClient } from './auth'; + +function LoginScreen() { + const authClient = useAuthClient(); + + return ( + authClient.login(credentials)} + onError={(err) => console.error(err)} + /> + ); +} +``` + +That's it - the button handles the full Google Sign-In flow and the auth client manages tokens, persistence, and state. + +--- + +## Web Setup + +### Configuration + +```ts +import { GoogleAuthClient } from '@forward-software/react-auth-google'; + +const googleAuth = new GoogleAuthClient({ + clientId: 'YOUR_GOOGLE_CLIENT_ID', + + // Optional + scopes: ['openid', 'profile', 'email'], // default + persistTokens: true, // default - stores tokens in localStorage + storageKey: '@react-auth/google-tokens', // default + ux_mode: 'popup', // 'popup' | 'redirect' + redirect_uri: undefined, // required if ux_mode is 'redirect' + hosted_domain: undefined, // restrict to a G Suite domain +}); +``` + +### Custom storage + +By default, the web adapter uses `localStorage`. You can provide a custom storage: + +```ts +const googleAuth = new GoogleAuthClient({ + clientId: 'YOUR_GOOGLE_CLIENT_ID', + storage: { + getItem: (key) => sessionStorage.getItem(key), + setItem: (key, value) => sessionStorage.setItem(key, value), + removeItem: (key) => sessionStorage.removeItem(key), + }, +}); +``` + +### GoogleSignInButton (Web) + +Renders Google's official branded sign-in button via the GSI script. + +```tsx + authClient.login(credentials)} + onError={(err) => console.error(err)} + + // Optional - Google button customization + theme="outline" // 'outline' | 'filled_blue' | 'filled_black' + size="large" // 'large' | 'medium' | 'small' + text="signin_with" // 'signin_with' | 'signup_with' | 'continue_with' | 'signin' + shape="rectangular" // 'rectangular' | 'pill' | 'circle' | 'square' + width={300} +/> +``` + +### Manual integration (without GoogleSignInButton) + +If you prefer full control over the UI, use the GSI utilities directly: + +```tsx +import { useEffect, useRef } from 'react'; +import { loadGsiScript, initializeGsi, renderGsiButton } from '@forward-software/react-auth-google/web/gsi'; +import { useAuthClient } from './auth'; + +function CustomLogin() { + const authClient = useAuthClient(); + const buttonRef = useRef(null); + + useEffect(() => { + async function setup() { + await loadGsiScript(); + initializeGsi({ + client_id: 'YOUR_GOOGLE_CLIENT_ID', + callback: (response) => { + authClient.login({ idToken: response.credential }); + }, + }); + if (buttonRef.current) { + renderGsiButton(buttonRef.current, { theme: 'outline', size: 'large' }); + } + } + setup(); + }, []); + + return
; +} +``` + +### Token refresh on web + +Google Identity Services on the web does **not** provide refresh tokens. When the ID token expires, the user must sign in again. The adapter handles this automatically - `onInit()` returns `null` when stored tokens are expired, which transitions the auth state to unauthenticated. + +--- + +## React Native / Expo Setup + +### Configuration + +```ts +import { GoogleAuthClient } from '@forward-software/react-auth-google'; +import { MMKV } from 'react-native-mmkv'; + +const mmkv = new MMKV(); + +const googleAuth = new GoogleAuthClient({ + clientId: 'YOUR_GOOGLE_CLIENT_ID', + webClientId: 'YOUR_WEB_CLIENT_ID', // required for ID token retrieval on Android + iosClientId: 'YOUR_IOS_CLIENT_ID', // iOS-specific client ID (if different) + + // Required on React Native - no default storage + storage: { + getItem: (key) => mmkv.getString(key) ?? null, + setItem: (key, value) => mmkv.set(key, value), + removeItem: (key) => mmkv.delete(key), + }, + + // Optional + scopes: ['openid', 'profile', 'email'], + persistTokens: true, + storageKey: '@react-auth/google-tokens', + offlineAccess: false, +}); +``` + +> **Note:** On React Native, a `storage` adapter is **required**. The adapter throws an error if none is provided. Use [react-native-mmkv](https://github.com/mrousavy/react-native-mmkv) (recommended) or wrap AsyncStorage with the `TokenStorage` interface. + +### GoogleSignInButton (React Native) + +Renders a styled button that triggers the native Google Sign-In flow. + +```tsx + authClient.login(credentials)} + onError={(err) => Alert.alert('Error', err.message)} + style={{ marginTop: 20 }} + disabled={false} +/> +``` + +### Manual integration (without GoogleSignInButton) + +```tsx +import { GoogleSignInModule } from '@forward-software/react-auth-google'; +import { useAuthClient } from './auth'; + +function LoginScreen() { + const authClient = useAuthClient(); + + const handleSignIn = async () => { + try { + const credentials = await GoogleSignInModule.signIn(); + await authClient.login(credentials); + } catch (err) { + console.error(err); + } + }; + + return