Implement sign in with apple

This commit is contained in:
Arthur Belleville 2025-08-01 22:49:54 +02:00
parent a179f4d5b9
commit 59ac499c3b
No known key found for this signature in database
6 changed files with 60 additions and 10 deletions

View file

@ -9,6 +9,7 @@
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"usesAppleSignIn": true,
"supportsTablet": true,
"bundleIdentifier": "com.xtablo.app",
"infoPlist": {
@ -38,7 +39,8 @@
"backgroundColor": "#ffffff"
}
],
"expo-secure-store"
"expo-secure-store",
"expo-apple-authentication"
],
"experiments": {
"typedRoutes": true

View file

@ -66,9 +66,6 @@ export default function RootLayout() {
const RootNavigator = () => {
const { isLoading, isLoggedIn } = useInitializeApp();
console.log("isLoading", isLoading);
console.log("isLoggedIn", isLoggedIn);
if (isLoading) {
return <LoadingView />;
}

View file

@ -5,6 +5,7 @@ import {
Text,
Image,
ImageSourcePropType,
Platform,
} from "react-native";
import { Button, Input } from "@rn-vui/themed";
import { useAuthStore } from "@/stores/auth";
@ -22,6 +23,7 @@ export default function Auth() {
const login = useAuthStore((state) => state.login);
const authLoading = useAuthStore((state) => state.loading);
const performOAuth = useAuthStore((state) => state.performOAuth);
const signInWithApple = useAuthStore((state) => state.signInWithApple);
// Theme-aware colors
const backgroundColor = useThemeColor(
@ -93,9 +95,12 @@ export default function Auth() {
<View style={styles.verticallySpaced}>
<GoogleLoginButton onPress={() => performOAuth("google")} />
</View>
<View style={[styles.verticallySpaced, styles.mt5]}>
<AppleLoginButton onPress={() => performOAuth("apple")} />
</View>
{Platform.OS === "ios" && (
<View style={[styles.verticallySpaced, styles.mt5]}>
<AppleLoginButton onPress={() => signInWithApple()} />
</View>
)}
<View style={styles.linkContainer}>
<Text style={[styles.linkText, { color: subtitleColor }]}>
Pas encore de compte ?{" "}

View file

@ -18,6 +18,7 @@
"@tanstack/react-query": "^5.75.2",
"aes-js": "^3.1.2",
"expo": "^53.0.19",
"expo-apple-authentication": "~7.2.4",
"expo-auth-session": "~6.2.1",
"expo-av": "~15.1.7",
"expo-blur": "~14.1.5",
@ -5704,6 +5705,15 @@
}
}
},
"node_modules/expo-apple-authentication": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/expo-apple-authentication/-/expo-apple-authentication-7.2.4.tgz",
"integrity": "sha512-T2agaLLPT4Ax97FeXImB7BCCEzEJ0gB+ZwlFa/FXBtbp6WFKcGRlTVKiX2YPYLZzN5QjXcmQ9HHJ17jRthNHMg==",
"peerDependencies": {
"expo": "*",
"react-native": "*"
}
},
"node_modules/expo-application": {
"version": "6.1.5",
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-6.1.5.tgz",

View file

@ -59,7 +59,8 @@
"react-native-webview": "13.13.5",
"stream-chat-expo": "^6.7.3",
"zustand": "^5.0.4",
"expo-dev-client": "~5.2.4"
"expo-dev-client": "~5.2.4",
"expo-apple-authentication": "~7.2.4"
},
"devDependencies": {
"@babel/core": "^7.25.2",

View file

@ -8,6 +8,7 @@ import { Linking } from "react-native";
import { QueryClient } from "@tanstack/react-query";
import { User } from "@/types/user.types";
import { api } from "@/lib/api";
import * as AppleAuthentication from "expo-apple-authentication";
interface AuthState {
session: Session | null;
@ -25,6 +26,7 @@ interface AuthState {
companyName: string
) => Promise<void>;
performOAuth: (provider: Provider) => Promise<void>;
signInWithApple: () => Promise<void>;
signOut: () => Promise<void>;
createSessionFromUrl: (url: string) => Promise<void>;
fetchAndSetUser: (session: Session | null) => Promise<void>;
@ -63,8 +65,6 @@ export const useAuthStore = create<AuthState>((set, get) => ({
});
supabase.auth.onAuthStateChange(async (event, session) => {
console.log("event", event);
console.log("session exists", !!session);
set({
session,
});
@ -139,6 +139,41 @@ export const useAuthStore = create<AuthState>((set, get) => ({
await get().createSessionFromUrl(url);
}
},
signInWithApple: async () => {
try {
const credential = await AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL,
],
});
if (credential.identityToken) {
const {
error,
data: { user, session },
} = await supabase.auth.signInWithIdToken({
provider: "apple",
token: credential.identityToken,
});
if (!error && user) {
const userProfile = {
id: user.id,
email: user.email ?? "",
name: user.user_metadata.name,
avatar_url: user.user_metadata.picture,
streamToken: user.user_metadata.streamToken,
};
await set({ user: userProfile, session });
}
} else {
throw new Error("No identityToken.");
}
} catch (e) {
console.error("Error signing in with Apple:", e);
}
},
signOut: async () => {
await supabase.auth.signOut();
set({ loading: false, user: null, session: null });