import React, { useState } from 'react'; import { StyleSheet, Alert } from 'react-native'; import * as WebBrowser from 'expo-web-browser'; import * as Linking from 'expo-linking'; import * as AuthSession from 'expo-auth-session'; import * as QueryParams from 'expo-auth-session/build/QueryParams'; import { supabase } from '@/lib/supabase'; import { ThemedView, ThemedButton, ThemedText } from '@/components/theme'; import { Colors } from '@/constants/Colors'; WebBrowser.maybeCompleteAuthSession(); // Configuration for Azure AD const tenantId = process.env.EXPO_PUBLIC_AZURE_TENANT_ID; const clientId = process.env.EXPO_PUBLIC_AZURE_CLIENT_ID; // Create MSAL auth request const redirectUri = Linking.createURL('auth/callback'); const discovery = { authorizationEndpoint: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`, tokenEndpoint: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, }; const AzureSignIn = () => { const [loading, setLoading] = useState(false); const signInWithAzure = async () => { try { setLoading(true); console.log('Starting Azure sign-in with tenant-specific endpoint'); console.log('Redirect URI:', redirectUri); // Create the MSAL auth request const request = new AuthSession.AuthRequest({ clientId: clientId!, scopes: ['openid', 'profile', 'email', 'offline_access', 'User.Read'], redirectUri, usePKCE: true, responseType: AuthSession.ResponseType.Code, }); // Generate the auth URL with PKCE const authUrl = await request.makeAuthUrlAsync(discovery); console.log('Generated auth URL:', authUrl); // Open the auth URL in a browser const result = await WebBrowser.openAuthSessionAsync( authUrl, redirectUri, { showInRecents: true, } ); console.log('Auth session result type:', result.type); if (result.type === 'success' && result.url) { // Parse the URL to get the authorization code const { params, errorCode } = QueryParams.getQueryParams(result.url); if (errorCode || params.error) { const errorMessage = params.error_description || params.error || errorCode; throw new Error(`Error during authentication: ${errorMessage}`); } if (!params.code) { throw new Error('No authorization code received'); } console.log('Authorization code received'); // Exchange the code for tokens const tokenResult = await AuthSession.exchangeCodeAsync( { clientId: clientId!, code: params.code, redirectUri, extraParams: { code_verifier: request.codeVerifier || '', }, }, discovery ); console.log('Token exchange successful'); if (!tokenResult.idToken) { throw new Error('No ID token received'); } // Now use the ID token to sign in with Supabase const { data, error } = await supabase.auth.signInWithIdToken({ provider: 'azure', token: tokenResult.idToken, }); if (error) { console.error('Supabase sign-in error:', error); throw error; } console.log('Successfully signed in with Azure via Supabase'); return data; } else { console.log('Authentication was canceled or failed'); } } catch (error: any) { console.error('Error signing in with Azure:', error); Alert.alert('Sign In Error', error.message || 'An error occurred during sign in'); } finally { setLoading(false); } }; return ( {loading ? "Signing in..." : "Sign in with Microsoft"} ); }; export default AzureSignIn; const styles = StyleSheet.create({ verticallySpaced: { paddingTop: 4, paddingBottom: 4, alignItems: 'center', marginTop: 20, }, });