Adding Authentication to Your Rork App
User authentication is a fundamental requirement for nearly every app. Because Rork generates React Native / Expo code, you can seamlessly integrate battle-tested authentication services like Firebase Authentication or Supabase Auth.
In this guide, we'll walk through two approaches to adding auth to a Rork-generated app:
- Firebase Authentication — Deep Google ecosystem integration, excellent for social login
- Supabase Auth — Open-source, PostgreSQL-native, developer-friendly API
Authentication Flow Overview
┌─────────────────────────────────────────────┐
│ App (Rork-generated code) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │LoginScreen│→│ AuthHook │→│HomeScreen│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ↕ │
│ Firebase / Supabase │
└─────────────────────────────────────────────┘
Rork projects use Expo Router under the hood. The recommended pattern is to manage auth state in a custom hook, then use a root layout guard to redirect unauthenticated users to the login screen.
Using Firebase Authentication
1. Create a Firebase Project
In the Firebase Console, create a project and enable Email/Password under Authentication → Sign-in method. Download google-services.json (Android) and GoogleService-Info.plist (iOS) for later.
2. Rork Prompt Example
Add email and password authentication to the app.
- Create a login screen and a sign-up screen
- Use Firebase Authentication
- Only authenticated users can access the home screen
- Add a logout button to the profile screen
Rork will generate all the necessary code. You'll only need to swap in your Firebase configuration values.
3. Firebase Configuration
Add a firebase.config.js file to your Rork project:
// firebase.config.js
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_PROJECT.firebaseapp.com",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_PROJECT.appspot.com",
messagingSenderId: "YOUR_SENDER_ID",
appId: "YOUR_APP_ID",
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);4. Auth Hook
// hooks/useAuth.js
import { useState, useEffect } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from '../firebase.config';
export function useAuth() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
setLoading(false);
});
return () => unsubscribe();
}, []);
return { user, loading };
}5. Login Screen
// app/login.jsx
import { useState } from 'react';
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../firebase.config';
import { router } from 'expo-router';
export default function LoginScreen() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleLogin = async () => {
try {
await signInWithEmailAndPassword(auth, email, password);
router.replace('/home');
} catch (e) {
setError('Invalid email or password. Please try again.');
}
};
return (
<View style={styles.container}>
<TextInput
placeholder="Email address"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
style={styles.input}
/>
<TextInput
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={styles.input}
/>
{error ? <Text style={styles.error}>{error}</Text> : null}
<Button title="Log In" onPress={handleLogin} />
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', padding: 20 },
input: {
borderWidth: 1, borderColor: '#ccc',
borderRadius: 8, padding: 12, marginBottom: 12,
},
error: { color: 'red', marginBottom: 8 },
});Using Supabase Auth
Supabase offers a simpler setup with excellent free-tier limits and native SQL support.
1. Create a Supabase Project
In the Supabase Dashboard, create a project, then go to Authentication → Providers and enable the Email provider. Note your Project URL and anon key.
2. Rork Prompt Example
Implement email authentication using Supabase.
- Send email verification on sign-up
- Login and logout functionality
- Redirect users based on auth state
3. Supabase Client Setup
// lib/supabase.js
import { createClient } from '@supabase/supabase-js';
import AsyncStorage from '@react-native-async-storage/async-storage';
export const supabase = createClient(
'https://YOUR_PROJECT.supabase.co',
'YOUR_ANON_KEY',
{
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
}
);Important: Using
AsyncStorageas the session storage ensures the user stays logged in after the app restarts.
4. Auth Hook (Supabase)
// hooks/useAuth.js
import { useState, useEffect } from 'react';
import { supabase } from '../lib/supabase';
export function useAuth() {
const [session, setSession] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
setLoading(false);
});
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => setSession(session)
);
return () => subscription.unsubscribe();
}, []);
return { session, user: session?.user, loading };
}5. Auth Operations
// Sign up
const { error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'securepassword',
});
// Log in
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'securepassword',
});
// Log out
await supabase.auth.signOut();Route Guard: Redirect Unauthenticated Users
With Expo Router, implement a route guard in _layout.jsx:
// app/_layout.jsx
import { useEffect } from 'react';
import { Slot, router, useSegments } from 'expo-router';
import { useAuth } from '../hooks/useAuth';
export default function RootLayout() {
const { user, loading } = useAuth();
const segments = useSegments();
useEffect(() => {
if (loading) return;
const inAuthGroup = segments[0] === '(auth)';
if (!user && !inAuthGroup) {
// Not logged in, trying to access protected screen → redirect to login
router.replace('/(auth)/login');
} else if (user && inAuthGroup) {
// Already logged in, on auth screen → redirect to home
router.replace('/home');
}
}, [user, loading, segments]);
return <Slot />;
}Firebase vs Supabase — Which Should You Choose?
| Feature | Firebase Auth | Supabase Auth |
|---|---|---|
| Free tier | 10,000 MAU/month | 50,000 MAU/month |
| Social login | ◎ (Google, Apple, Twitter, etc.) | ○ (major providers) |
| Database | Firestore (NoSQL) | PostgreSQL (SQL) |
| Open source | ✗ (Google proprietary) | ✓ |
| Learning curve | Medium | Low |
| Rork compatibility | ◎ | ◎ |
For indie developers and MVPs, Supabase is the go-to choice — the free tier is generous and the API is intuitive. If Google/Apple Sign-In is a priority, Firebase is the more mature option.
Bonus: Adding Social Login
You can add social login with a simple prompt addition:
Also add Google Sign-In and Apple Sign-In buttons.
Use expo-auth-session for the implementation.
App Store Requirement: If your app offers any third-party login, Apple requires you to also offer Sign in with Apple. Don't skip this if you plan to ship on iOS.
Looking back
- Rork generates React Native / Expo code, making it fully compatible with both Firebase and Supabase
- Manage auth state centrally using a custom hook, then enforce it with a root layout guard
- Choose Firebase for Google ecosystem depth; choose Supabase for open-source SQL flexibility
- Always subscribe to
onAuthStateChanged/onAuthStateChangefor real-time auth state tracking
Adding authentication unlocks per-user data management, personalization, and a host of other features that elevate your app from a prototype to a real product. Give it a try in your next Rork project.