From 9f13d0357a3d3709af6d4972d1e4fad902d20519 Mon Sep 17 00:00:00 2001 From: gibbyb Date: Thu, 6 Mar 2025 16:55:13 -0600 Subject: [PATCH] Start trying to support Microsoft Azure Sign in --- app.json | 5 +- ...leSignIn.native.tsx => AppleSignIniOS.tsx} | 25 ++-- components/auth/Auth.tsx | 4 +- components/auth/AzureSignIn.tsx | 109 ++++++++++++++++++ package-lock.json | 31 +++++ package.json | 3 +- services/PushNotificationManager.tsx | 1 + 7 files changed, 167 insertions(+), 11 deletions(-) rename components/auth/{AppleSignIn.native.tsx => AppleSignIniOS.tsx} (80%) create mode 100644 components/auth/AzureSignIn.tsx diff --git a/app.json b/app.json index d98ae4b..68e9a3c 100644 --- a/app.json +++ b/app.json @@ -33,7 +33,10 @@ }, "permissions": [ "android.permission.ACCESS_COARSE_LOCATION", - "android.permission.ACCESS_FINE_LOCATION" + "android.permission.ACCESS_FINE_LOCATION", + "android.permission.RECEIVE_BOOT_COMPLETED", + "android.permission.VIBRATE", + "android.permission.INTERNET" ], "package": "com.gbrown.techtracker" }, diff --git a/components/auth/AppleSignIn.native.tsx b/components/auth/AppleSignIniOS.tsx similarity index 80% rename from components/auth/AppleSignIn.native.tsx rename to components/auth/AppleSignIniOS.tsx index ad22c7f..e74a059 100644 --- a/components/auth/AppleSignIn.native.tsx +++ b/components/auth/AppleSignIniOS.tsx @@ -24,6 +24,7 @@ const AppleSignInButton = () => { //projectId, //}); if (credential.identityToken) { + const email = credential.email; const full_name = ( credential.fullName && credential.fullName.givenName && @@ -41,16 +42,26 @@ const AppleSignInButton = () => { }); console.log(JSON.stringify({ error, user }, null, 2)) if (!error) { - if (user) { - const data: any = { - full_name, - }; + if (user && session) { + const data: any = {}; + if (email) data.email = email; + if (full_name) data.full_name = full_name; const { error: updateError } = await supabase.auth.updateUser({ data, }); if (updateError) { console.error('Error updating user metadata:', updateError); } + const { error: updateProfileError } = + await supabase.from('profiles').upsert({ + id: session.user.id, + username: data?.email.split('@')[0], + full_name: data?.full_name, + updated_at: new Date(), + }); + if (updateProfileError) { + console.error('Error updating profile:', updateProfileError); + } } } } else { @@ -67,10 +78,10 @@ const AppleSignInButton = () => { } } - if (Platform.OS !== 'ios') return
; + if (Platform.OS !== 'ios') return ; else return ( - + { /> + ); }; diff --git a/components/auth/AzureSignIn.tsx b/components/auth/AzureSignIn.tsx new file mode 100644 index 0000000..99bbcc2 --- /dev/null +++ b/components/auth/AzureSignIn.tsx @@ -0,0 +1,109 @@ +import React, { useState } from 'react'; +import * as WebBrowser from 'expo-web-browser'; +import { makeRedirectUri, useAuthRequest, useAutoDiscovery } from 'expo-auth-session'; +import { Platform, StyleSheet } from 'react-native'; +import { supabase } from '@/lib/supabase'; +import { ThemedView, ThemedTextButton } from '@/components/theme'; + +// This is important - it completes the auth session when the browser redirects back to your app +WebBrowser.maybeCompleteAuthSession(); + +const AzureSignIn = () => { + const [loading, setLoading] = useState(false); + + // Get environment variables + const tenantId = process.env.EXPO_PUBLIC_AZURE_TENANT_ID as string; + const clientId = process.env.EXPO_PUBLIC_AZURE_CLIENT_ID as string; + + // Set up the discovery endpoint for Azure AD + const discovery = useAutoDiscovery( + `https://login.microsoftonline.com/${tenantId}/v2.0` + ); + + // Create a redirect URI that matches what you configured in Azure + // This should match the redirect URI you set in your Supabase dashboard + const redirectUri = makeRedirectUri({ + scheme: Platform.OS === 'web' ? undefined : 'com.gbrown.techtracker', + path: Platform.OS === 'web' ? 'auth/callback' : undefined, + }); + + // Set up the auth request with the needed scopes + const [request, response, promptAsync] = useAuthRequest( + { + clientId, + scopes: ['openid', 'profile', 'email', 'offline_access'], + redirectUri, + responseType: 'code', // Important for Supabase + usePKCE: true, // Use PKCE for added security + }, + discovery + ); + + const signInWithAzure = async () => { + try { + setLoading(true); + + // For Expo Go and mobile apps, we need to use the Expo Auth Session flow + if (Platform.OS !== 'web') { + // Launch the browser for authentication + const result = await promptAsync(); + + if (result.type === 'success') { + // If we got an authorization code, use Supabase to exchange it for a session + const { code } = result.params; + + const { data, error } = await supabase.auth.exchangeCodeForSession(code); + + if (error) { + throw error; + } + + console.log('Successfully signed in with Azure!', data.user); + } else if (result.type === 'error') { + throw new Error(result.error?.message || 'Authentication failed'); + } else if (result.type === 'cancel') { + console.log('User cancelled the login flow'); + } + } else { + // For web, we can use Supabase's built-in OAuth flow + const { data, error } = await supabase.auth.signInWithOAuth({ + provider: 'azure', + options: { + scopes: 'email profile openid offline_access', + redirectTo: window.location.origin + '/auth/callback', + }, + }); + + if (error) { + throw error; + } + } + } catch (error) { + console.error('Error signing in with Azure:', error); + alert(`Error signing in: ${error.message}`); + } finally { + setLoading(false); + } + }; + + return ( + + + + ); +}; +export default AzureSignIn; + +const styles = StyleSheet.create({ + verticallySpaced: { + paddingTop: 4, + paddingBottom: 4, + alignItems: 'center', + marginTop: 20, + }, +}); diff --git a/package-lock.json b/package-lock.json index 883f787..011572d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "aes-js": "^3.1.2", "expo": "~52.0.28", "expo-apple-authentication": "~7.1.3", + "expo-auth-session": "~6.0.3", "expo-blur": "~14.0.3", "expo-constants": "~17.0.7", "expo-dev-client": "~5.0.12", @@ -7668,6 +7669,24 @@ "react-native": "*" } }, + "node_modules/expo-auth-session": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/expo-auth-session/-/expo-auth-session-6.0.3.tgz", + "integrity": "sha512-s7LmmMPiiY1NXrlcXkc4+09Hlfw9X1CpaQOCDkwfQEodG1uCYGQi/WImTnDzw5YDkWI79uC8F1mB8EIerilkDA==", + "license": "MIT", + "dependencies": { + "expo-application": "~6.0.2", + "expo-constants": "~17.0.5", + "expo-crypto": "~14.0.2", + "expo-linking": "~7.0.5", + "expo-web-browser": "~14.0.2", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-blur": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/expo-blur/-/expo-blur-14.0.3.tgz", @@ -7693,6 +7712,18 @@ "react-native": "*" } }, + "node_modules/expo-crypto": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-14.0.2.tgz", + "integrity": "sha512-WRc9PBpJraJN29VD5Ef7nCecxJmZNyRKcGkNiDQC1nhY5agppzwhqh7zEzNFarE/GqDgSiaDHS8yd5EgFhP9AQ==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-dev-client": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-5.0.12.tgz", diff --git a/package.json b/package.json index aedb769..17fbdaa 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,8 @@ "@expo/ngrok": "4.1.0", "expo-notifications": "~0.29.13", "expo-device": "~7.0.2", - "expo-location": "~18.0.7" + "expo-location": "~18.0.7", + "expo-auth-session": "~6.0.3" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/services/PushNotificationManager.tsx b/services/PushNotificationManager.tsx index 8b63869..c673189 100644 --- a/services/PushNotificationManager.tsx +++ b/services/PushNotificationManager.tsx @@ -72,6 +72,7 @@ async function registerForPushNotificationsAsync() { } const projectId = Constants.expoConfig?.extra?.eas?.projectId; if (!projectId) { + console.warn('No project id found'); alert('Project ID not found'); return; }