# Frontend Authentication Flow with Middleware and Supabase This document outlines how to authenticate your frontend applications (web, React Native, etc.) with the middleware service that issues Supabase-compatible JWTs. ## Overview The authentication flow works as follows: 1. Frontend app authenticates with middleware service 2. Middleware issues a Supabase-compatible JWT token 3. Frontend sets this token as the Supabase session 4. All Supabase operations now respect RLS policies ## Integration Steps ### 1. Set Up Supabase Client ```javascript // For React Native import { createClient } from '@supabase/supabase-js'; import AsyncStorage from '@react-native-async-storage/async-storage'; // Custom storage adapter for React Native const AsyncStorageAdapter = { getItem: async (key) => await AsyncStorage.getItem(key), setItem: async (key, value) => await AsyncStorage.setItem(key, value), removeItem: async (key) => await AsyncStorage.removeItem(key), }; // Initialize Supabase client export const supabase = createClient( SUPABASE_URL, SUPABASE_ANON_KEY, { auth: { storage: AsyncStorageAdapter, // For React Native autoRefreshToken: true, persistSession: true, detectSessionInUrl: false, }, } ); // For Web applications, you can use built-in storage export const supabase = createClient( SUPABASE_URL, SUPABASE_ANON_KEY, { auth: { autoRefreshToken: true, persistSession: true, }, } ); ``` ### 2. Implement Authentication with Middleware ```javascript // Sign in with middleware service export const signInWithMiddleware = async (email, password) => { try { // 1. Authenticate with middleware const response = await fetch('https://your-middleware-api.com/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Authentication failed'); } // 2. Get Supabase-compatible JWT const { token, refreshToken } = await response.json(); // 3. Set the Supabase session const { data, error } = await supabase.auth.setSession({ access_token: token, refresh_token: refreshToken || '', }); if (error) throw error; return { user: data.user, session: data.session }; } catch (error) { console.error('Error signing in:', error.message); throw error; } }; ``` ### 3. Session Management ```javascript // Sign out export const signOut = async () => { try { const { error } = await supabase.auth.signOut(); if (error) throw error; } catch (error) { console.error('Error signing out:', error.message); throw error; } }; // Get current session export const getSession = async () => { try { const { data, error } = await supabase.auth.getSession(); if (error) throw error; return data.session; } catch (error) { console.error('Error getting session:', error.message); return null; } }; // Refresh token when needed export const refreshSession = async () => { try { const { data, error } = await supabase.auth.refreshSession(); if (error) throw error; return data.session; } catch (error) { console.error('Error refreshing session:', error.message); return null; } }; ``` ### 4. Auth State Management ```javascript // React Hook for auth state import { useState, useEffect } from 'react'; export const useAuth = () => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // Get initial session const initializeAuth = async () => { try { const session = await getSession(); setUser(session?.user || null); } finally { setLoading(false); } }; initializeAuth(); // Listen for auth state changes const { data: authListener } = supabase.auth.onAuthStateChange( (event, session) => { setUser(session?.user || null); } ); return () => { if (authListener?.subscription) { authListener.subscription.unsubscribe(); } }; }, []); return { user, loading, signIn: signInWithMiddleware, signOut }; }; ``` ### 5. Complete Example in React Native ```jsx import React from 'react'; import { View, TextInput, Button, Text } from 'react-native'; import { useAuth } from './auth'; export default function AuthScreen() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const { user, loading, signIn, signOut } = useAuth(); const handleLogin = async () => { try { setError(null); await signIn(email, password); } catch (err) { setError(err.message); } }; if (loading) { return Loading...; } return ( {user ? ( Logged in as: {user.email}