110 lines
3.5 KiB
TypeScript
110 lines
3.5 KiB
TypeScript
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 (
|
|
<ThemedView style={styles.verticallySpaced}>
|
|
<ThemedTextButton
|
|
text="Sign in with Microsoft"
|
|
disabled={loading || !request}
|
|
onPress={signInWithAzure}
|
|
fontSize={18}
|
|
/>
|
|
</ThemedView>
|
|
);
|
|
};
|
|
export default AzureSignIn;
|
|
|
|
const styles = StyleSheet.create({
|
|
verticallySpaced: {
|
|
paddingTop: 4,
|
|
paddingBottom: 4,
|
|
alignItems: 'center',
|
|
marginTop: 20,
|
|
},
|
|
});
|