useGoogleAuth

Authentication Hook

There are not many resources on Supabase Google authentication within React Native Expo apps. What I found was not well structured, in my opinion. For that reason, I built a hook from scratch to handle the process.

useGoogleAuth
1
import * as QueryParams from "expo-auth-session/build/QueryParams";
2
3
import { useState } from "react";
4
5
import logError from "@/lib/logError";
6
import { supabase } from "@/lib/supabase";
7
8
import * as Linking from "expo-linking";
9
import * as WebBrowser from "expo-web-browser";
10
11
WebBrowser.maybeCompleteAuthSession();
12
13
type GoogleAuthError = {
14
code: string;
15
message: string;
16
};
17
18
type GoogleAuthState = {
19
isLoading: boolean;
20
error: GoogleAuthError | null;
21
};
22
23
export default function useGoogleAuth() {
24
const [state, setState] = useState<GoogleAuthState>({
25
isLoading: false,
26
error: null,
27
});
28
29
const createSessionFromUrl = async (url: string) => {
30
try {
31
const { params, errorCode } = QueryParams.getQueryParams(url);
32
33
if (errorCode) return { error: "An error occurred" };
34
35
const { access_token, refresh_token } = params;
36
if (!access_token) return { error: "Something went wrong" };
37
38
const { data, error } = await supabase.auth.setSession({
39
access_token,
40
refresh_token,
41
});
42
43
if (error) return { error };
44
return { session: data.session };
45
} catch (error) {
46
logError("createSessionFromUrl", error);
47
return { error: "Session creation failed" };
48
}
49
};
50
51
const performOAuth = async () => {
52
try {
53
const { data, error } = await supabase.auth.signInWithOAuth({
54
provider: "google",
55
options: {
56
redirectTo: Linking.createURL("/"),
57
skipBrowserRedirect: true,
58
queryParams: {
59
prompt: "select_account",
60
},
61
},
62
});
63
64
if (error) return { error: "An error occurred" };
65
if (!data?.url) return { error: "Something went wrong" };
66
67
const response = await WebBrowser.openAuthSessionAsync(
68
data.url,
69
Linking.createURL("/")
70
);
71
72
if (response.type === "success" && response.url) {
73
await createSessionFromUrl(response.url);
74
}
75
return { error: "Authentication canceled or failed" };
76
} catch (error) {
77
logError("performOAuth", error);
78
return { error: "Authentication failed" };
79
}
80
};
81
82
const handleGoogleAuth = async () => {
83
setState(prev => ({ ...prev, isLoading: true, error: null }));
84
const { error } = await performOAuth();
85
if (error) return setState(prev => ({ ...prev, isLoading: false, error: { code: "AUTH_ERROR", message: error } }));
86
else return setState(prev => ({ ...prev, isLoading: false }));
87
};
88
89
return {
90
handleGoogleAuth,
91
isLoading: state.isLoading,
92
error: state.error,
93
};
94
}