summaryrefslogtreecommitdiff
path: root/lib/google-auth.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/google-auth.ts')
-rw-r--r--lib/google-auth.ts116
1 files changed, 116 insertions, 0 deletions
diff --git a/lib/google-auth.ts b/lib/google-auth.ts
new file mode 100644
index 0000000..769da55
--- /dev/null
+++ b/lib/google-auth.ts
@@ -0,0 +1,116 @@
+import { ResponseType } from "expo-auth-session";
+import * as Google from "expo-auth-session/providers/google";
+import Constants from "expo-constants";
+import * as WebBrowser from "expo-web-browser";
+import { useEffect, useMemo, useState } from "react";
+import { useAuth } from "./auth";
+import { t } from "./locales";
+
+WebBrowser.maybeCompleteAuthSession();
+
+type GoogleClientIds = {
+ iosClientId?: string;
+ androidClientId?: string;
+ webClientId?: string;
+};
+
+function getGoogleClientIds(): GoogleClientIds {
+ const env = (process as any)?.env || {};
+ const extra =
+ (Constants.manifest as any)?.extra ||
+ (Constants.expoConfig as any)?.extra ||
+ {};
+
+ return {
+ iosClientId:
+ env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID || extra.GOOGLE_IOS_CLIENT_ID,
+ androidClientId:
+ env.EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID ||
+ extra.GOOGLE_ANDROID_CLIENT_ID,
+ webClientId:
+ env.EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID ||
+ extra.GOOGLE_WEB_CLIENT_ID ||
+ env.EXPO_PUBLIC_GOOGLE_EXPO_CLIENT_ID ||
+ extra.GOOGLE_EXPO_CLIENT_ID,
+ };
+}
+
+export function useGoogleAuth() {
+ const { signInWithGoogle } = useAuth();
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState("");
+
+ const clientIds = useMemo(() => getGoogleClientIds(), []);
+
+ const [request, response, promptAsync] = Google.useAuthRequest({
+ iosClientId: clientIds.iosClientId,
+ androidClientId: clientIds.androidClientId,
+ webClientId: clientIds.webClientId,
+ responseType: ResponseType.IdToken,
+ scopes: ["openid", "profile", "email"],
+ selectAccount: true,
+ });
+
+ useEffect(() => {
+ const run = async () => {
+ if (!response) return;
+
+ if (response.type === "success") {
+ const idToken =
+ response.params?.id_token || response.authentication?.idToken;
+
+ if (!idToken) {
+ setError(t("googleMissingIdToken"));
+ setIsLoading(false);
+ return;
+ }
+
+ const result = await signInWithGoogle(idToken);
+ if (!result.success) {
+ setError(result.reason || t("googleSignInError"));
+ }
+ setIsLoading(false);
+ return;
+ }
+
+ if (response.type === "error") {
+ setError(response.error?.message || t("googleSignInError"));
+ }
+
+ // On cancel/dismissed/locked, just reset loading and keep the current screen state.
+ setIsLoading(false);
+ };
+
+ run().catch(() => {
+ setError(t("googleSignInError"));
+ setIsLoading(false);
+ });
+ }, [response, signInWithGoogle]);
+
+ const continueWithGoogle = async () => {
+ setError("");
+
+ if (!request) {
+ setError(t("googleConfigMissing"));
+ return;
+ }
+
+ setIsLoading(true);
+
+ try {
+ const result = await promptAsync();
+ if (result.type === "cancel" || result.type === "dismiss") {
+ setIsLoading(false);
+ }
+ } catch {
+ setError(t("googleSignInError"));
+ setIsLoading(false);
+ }
+ };
+
+ return {
+ continueWithGoogle,
+ isLoading,
+ error,
+ };
+}