Authenticatieflow en beveiligde routes
Implementeer registratie, inloggen en het bewaren van sessies, stel een root navigator in die wisselt tussen auth- en app-stacks en bescherm alle gegevensschermen tegen toegang zonder authenticatie.
Authenticatieflow en beveiligde routes is een gratis React Native Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject React Native Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus React Native Academy bevat in totaal 4 lessen.
Overzicht van de authenticatiearchitectuur
Een authenticatiestroom voor productie heeft drie toestanden die je navigator moet afhandelen: laden (controleren of er een sessie in de opslag bestaat), niet geauthenticeerd (authenticatieschermen tonen) en geauthenticeerd (appschermen tonen). Het belangrijkste inzicht is dat je hoofdnavigator op basis van de sessiestatus wisselt tussen de authenticatiestack en de appstack — gebruikers kunnen geen toegang krijgen tot gegevensschermen zonder een geldige sessie en geauthenticeerde gebruikers kunnen niet op het inlogscherm terechtkomen.
// Auth states:
// 'loading' -> Show a splash/loading screen
// 'unauthenticated' -> Show auth stack (Sign In, Sign Up)
// 'authenticated' -> Show app stack (tabs, data screens)
// The navigator reads session from AuthContext:
const { session, isLoading } = useAuth();
if (isLoading) return <SplashScreen />;
return (
<NavigationContainer>
{session ? <AppNavigator /> : <AuthNavigator />}
</NavigationContainer>
);AuthContext instellen
Maak een AuthContext die de huidige sessie, het gebruikersobject en de functies voor inloggen, registreren en uitloggen beschikbaar maakt voor de volledige componentenboom. Controleer bij het mounten AsyncStorage of de automatisch herstelde sessie van Supabase om te bepalen of de gebruiker al is ingelogd tijdens een eerdere start van de app. Zo voorkom je dat de authenticatieschermen kort verschijnen voordat de sessie is hersteld.
// src/context/AuthContext.tsx
import React, { createContext, useContext, useEffect, useState } from 'react';
import { Session } from '@supabase/supabase-js';
import { supabase } from '../services/supabase';
interface AuthContextType {
session: Session | null;
isLoading: boolean;
signOut: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType>(null!);
export function AuthProvider({ children }) {
const [session, setSession] = useState<Session | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
supabase.auth.getSession().then(({ data }) => {
setSession(data.session);
setIsLoading(false);
});
const { data: listener } = supabase.auth.onAuthStateChange(
(_event, session) => setSession(session)
);
return () => listener.subscription.unsubscribe();
}, []);
const signOut = async () => { await supabase.auth.signOut(); };
return (
<AuthContext.Provider value={{ session, isLoading, signOut }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);De app omwikkelen met AuthProvider
Omwikkel je volledige applicatie op het toegangspunt met AuthProvider, zodat elke component toegang heeft tot de sessie. Plaats deze buiten NavigationContainer, omdat de navigator zelf de auth-context uitleest. Omwikkel de app ook met QueryClientProvider als je React Query gebruikt. De volgorde is belangrijk: gegevensproviders moeten de navigatie omwikkelen en niet binnen specifieke schermen worden genest.
// App.tsx (entry point)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { AuthProvider } from './src/context/AuthContext';
import { RootNavigator } from './src/navigation/RootNavigator';
const queryClient = new QueryClient();
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<RootNavigator />
</AuthProvider>
</QueryClientProvider>
);
}Het registratiescherm implementeren
Het registratiescherm verzamelt e-mailadres en wachtwoord, valideert deze lokaal en roept supabase.auth.signUp() aan. Na een geslaagde registratie kan Supabase e-mailbevestiging vereisen — handel dit af door het bericht 'Controleer je e-mail' te tonen in plaats van meteen te navigeren. Gebruik react-hook-form voor validatie, zodat je niet voor elk veld handmatig de foutstatus hoeft te beheren.
// src/screens/auth/SignUpScreen.tsx
import { useForm, Controller } from 'react-hook-form';
import { supabase } from '../../services/supabase';
export function SignUpScreen({ navigation }) {
const { control, handleSubmit, formState: { errors } } = useForm();
const [message, setMessage] = useState('');
const onSubmit = async ({ email, password }) => {
const { error } = await supabase.auth.signUp({ email, password });
if (error) {
setMessage(error.message);
} else {
setMessage('Check your email to confirm your account!');
}
};
return (
<View>
<Controller
control={control}
name='email'
rules={{ required: true, pattern: /^[^@]+@[^@]+$/ }}
render={({ field: { onChange, value } }) => (
<TextInput
value={value}
onChangeText={onChange}
placeholder='Email'
keyboardType='email-address'
/>
)}
/>
{/* Password field similar pattern */}
<Button title='Sign Up' onPress={handleSubmit(onSubmit)} />
{message ? <Text>{message}</Text> : null}
</View>
);
}Het inlogscherm en sessiebehoud
Het inlogscherm roept supabase.auth.signInWithPassword() aan. Bij succes slaat Supabase de sessie op in AsyncStorage (geconfigureerd tijdens het instellen van de client) en wordt de listener onAuthStateChange in AuthContext geactiveerd, waardoor de sessiestatus wordt bijgewerkt. De hoofdnavigator detecteert de nieuwe sessie en navigeert automatisch naar de appstack — je hoeft na het inloggen niet handmatig navigation.navigate aan te roepen.
// Sign-in logic (simplified)
const signIn = async (email, password) => {
setLoading(true);
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
setLoading(false);
if (error) {
// Show error to user
Alert.alert('Sign In Error', error.message);
return;
}
// No navigation.navigate() needed!
// AuthContext.onAuthStateChange fires automatically
// -> session is set -> root navigator switches to AppNavigator
};Hoofdnavigator met authenticatiebewaking
De hoofdnavigator is de poortwachter die op basis van de sessiestatus bepaalt welke navigatiestructuur wordt weergegeven. Hij rendert zelf geen gebruikersinterface, maar delegeert aan AuthNavigator of AppNavigator. Omdat React Navigation opnieuw rendert wanneer de navigatiestructuur verandert (auth → app), worden gebruikers automatisch naar de juiste schermen doorgestuurd zonder expliciete navigatieaanroepen bij in- of uitloggen.
// src/navigation/RootNavigator.tsx
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { useAuth } from '../context/AuthContext';
import { AuthNavigator } from './AuthNavigator';
import { AppTabNavigator } from './AppTabNavigator';
import { SplashScreen } from '../screens/SplashScreen';
const Stack = createStackNavigator();
export function RootNavigator() {
const { session, isLoading } = useAuth();
if (isLoading) {
return <SplashScreen />; // Full-screen loading state
}
return (
<NavigationContainer>
{session ? (
<AppTabNavigator /> // Authenticated: show app screens
) : (
<AuthNavigator /> // Unauthenticated: show auth screens
)}
</NavigationContainer>
);
}Afzonderlijke schermen beveiligen
Het patroon met de hoofdnavigator beveiligt volledige navigatiestructuren. Soms heb je echter beveiliging binnen een scherm nodig — bijvoorbeeld voor een functie die alleen beschikbaar is voor premiumgebruikers. Maak een hook useRequireAuth die de sessie controleert en naar het inlogscherm navigeert als die ontbreekt. Of maak een omvattende component ProtectedRoute. Dit patroon is nuttig voor schermen die via een deep link kunnen worden geopend voordat de gebruiker is geauthenticeerd.
// src/hooks/useRequireAuth.ts
import { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';
import { useAuth } from '../context/AuthContext';
export function useRequireAuth() {
const { session, isLoading } = useAuth();
const navigation = useNavigation();
useEffect(() => {
if (!isLoading && !session) {
navigation.navigate('SignIn' as never);
}
}, [session, isLoading, navigation]);
return { session, isLoading };
}
// Usage in a screen:
export function PremiumFeatureScreen() {
const { session } = useRequireAuth();
if (!session) return null; // Navigation already happening
return <View>...</View>;
}Verlopen van tokens afhandelen
JWT-tokens van Supabase verlopen (meestal na 1 uur). De Supabase-client die is geconfigureerd met autoRefreshToken: true handelt dit automatisch af — de client vernieuwt het token op de achtergrond voordat het verloopt. Als het vernieuwen mislukt (bijvoorbeeld omdat het vernieuwingstoken is ingetrokken), wordt onAuthStateChange geactiveerd met een gebeurtenis SIGNED_OUT en wist je AuthContext de sessie. De navigator toont vervolgens automatisch de authenticatieschermen, zodat de gebruiker opnieuw kan inloggen.
// Token expiry handling is automatic with Supabase:
// supabase client config (already set):
// {
// auth: {
// autoRefreshToken: true, <- handles renewal automatically
// persistSession: true,
// storage: AsyncStorage,
// }
// }
// Your AuthContext listener handles SIGNED_OUT:
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_OUT') {
// session is null -> navigator shows auth screens
setSession(null);
}
if (event === 'TOKEN_REFRESHED') {
// New session with fresh tokens
setSession(session);
}
});Stroom voor het opnieuw instellen van het wachtwoord
Implementeer Wachtwoord vergeten met resetPasswordForEmail() van Supabase. De gebruiker voert diens e-mailadres in, Supabase verstuurt een koppeling voor het opnieuw instellen en wanneer de gebruiker daarop klikt, verwijst de koppeling via een deep link terug naar de app met een token. Je configureert de omleidings-URL in de auth-instellingen van het Supabase-dashboard. Luister aan de kant van de app naar de auth-gebeurtenis PASSWORD_RECOVERY en navigeer naar een scherm voor een nieuw wachtwoord.
// Step 1: Send reset email
const resetPassword = async (email) => {
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: 'habittracker://reset-password',
});
if (!error) Alert.alert('Email sent', 'Check your inbox.');
};
// Step 2: Handle deep link in AuthContext
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'PASSWORD_RECOVERY') {
// Navigate to update password screen
navigationRef.current?.navigate('UpdatePassword');
}
});
// Step 3: Update password screen
const updatePassword = async (newPassword) => {
const { error } = await supabase.auth.updateUser({
password: newPassword,
});
if (!error) navigation.navigate('Home');
};Uitloggen en de sessie opruimen
Bij het uitloggen moet alle lokale status worden gewist, niet alleen de Supabase-sessie. Roep supabase.auth.signOut() aan; hiermee wordt de sessie uit AsyncStorage verwijderd en de gebeurtenis SIGNED_OUT geactiveerd. Wis ook de React Query-cache, zodat de volgende gebruiker die op hetzelfde apparaat inlogt niet de gegevens van de vorige gebruiker ziet. Stel de navigatiestatus opnieuw in als je schermspecifieke status in de navigator hebt.
// Complete sign-out
const signOut = async () => {
// 1. Sign out from Supabase (clears AsyncStorage session)
await supabase.auth.signOut();
// 2. Clear React Query cache
queryClient.clear();
// 3. AuthContext detects SIGNED_OUT -> session = null
// 4. RootNavigator switches to AuthNavigator automatically
// No navigation.navigate() needed!
};
// In a Settings screen:
<TouchableOpacity onPress={signOut}>
<Text>Sign Out</Text>
</TouchableOpacity>De authenticatiestroom testen
Test elk authenticatiepad voordat je verdergaat met de ontwikkeling van functies: registratie van een nieuwe gebruiker (stroom voor e-mailbevestiging), inloggen van een bestaande gebruiker, fout bij een verkeerd wachtwoord, behoud van de sessie na het opnieuw starten van de app, uitloggen en het opnieuw instellen van het wachtwoord. Automatiseer het geslaagde pad met een Maestro-test. Controleer of de navigator correct wisselt tussen de authenticatie- en appstatus zonder te flikkeren — de laadstatus voorkomt dit flikkeren bij het controleren van AsyncStorage tijdens het opstarten.
# Maestro test for sign-in flow
---
appId: com.yourcompany.habittracker
---
- launchApp:
clearState: true
- assertVisible: 'Sign In'
- tapOn: 'Email'
- inputText: 'test@example.com'
- tapOn: 'Password'
- inputText: 'TestPass123!'
- tapOn: 'Sign In'
- waitForAnimationToEnd
- assertVisible: 'My Habits' # First app screen
- tapOn: 'Settings'
- tapOn: 'Sign Out'
- waitForAnimationToEnd
- assertVisible: 'Sign In' # Back to auth screenKorte toets
Toets je begrip van de concepten voor mobiele ontwikkeling met React Native uit deze les.
Samenvatting van de les
In deze les heb je geleerd hoe je een AuthContext bouwt die de sessiestatus bijhoudt en zich abonneert op auth-gebeurtenissen van Supabase, hoe de hoofdnavigator de sessiestatus gebruikt om te wisselen tussen authenticatie- en appnavigatiestructuren en hoe je stromen voor registreren, inloggen, uitloggen en het opnieuw instellen van wachtwoorden implementeert. Je hebt ook gezien hoe je de React Query-cache wist bij het uitloggen om gegevenslekken tussen gebruikers te voorkomen. Hierna bouwen we de centrale gegevensfeed met ondersteuning voor offlinegebruik.
Leer JavaScript met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 30
- Lessen
- 120
Veelgestelde vragen
Is de les “Authenticatieflow en beveiligde routes” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad React Native Academy, waaronder “Authenticatieflow en beveiligde routes”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus React Native Academy bevat in totaal 4 lessen.
Wat leer ik in “Authenticatieflow en beveiligde routes”?
Implementeer registratie, inloggen en het bewaren van sessies, stel een root navigator in die wisselt tussen auth- en app-stacks en bescherm alle gegevensschermen tegen toegang zonder authenticatie. Je oefent met React Native Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met React Native Academy te beginnen?
Ervaring vooraf is niet nodig. React Native Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Authenticatieflow en beveiligde routes”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over React Native Academy?
Ja. Elke les over React Native Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Architectuur en technologiestack plannen
- Authenticatieflow en beveiligde routes
- Kernfunctie: datafeed met offline-ondersteuning
- Afwerking, testen en publiceren in beide stores