This document describes the authentication system implemented for Gear AI CoPilot MVP. The system uses Firebase Authentication for user management and automatically syncs user data to a Supabase PostgreSQL database.
lib/firebase.ts)
lib/supabase.ts)
services/auth-service.ts)
contexts/AuthContext.tsx)
app/login.tsx)
Copy .env.local and configure with your credentials:
# Firebase Configuration
FIREBASE_API_KEY=your_firebase_api_key
FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
FIREBASE_PROJECT_ID=your_project_id
FIREBASE_STORAGE_BUCKET=your_project.appspot.com
FIREBASE_MESSAGING_SENDER_ID=your_sender_id
FIREBASE_APP_ID=your_app_id
FIREBASE_MEASUREMENT_ID=G-XXXXXXXXXX
# Supabase Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your_anon_key
.env.localsupabase/migrations/:
supabase db push
.env.localThe system creates users in the public.users table with the following structure:
CREATE TABLE public.users (
user_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
firebase_uid VARCHAR(128) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
display_name VARCHAR(255),
avatar_url TEXT,
tier VARCHAR(20) DEFAULT 'free',
stripe_customer_id VARCHAR(255),
subscription_status VARCHAR(50) DEFAULT 'none',
subscription_period_end TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
last_login_at TIMESTAMP,
preferences JSONB DEFAULT '{}'::jsonb
);
import { useAuth } from '../contexts/AuthContext';
function SignUpComponent() {
const { signUp } = useAuth();
const handleSignUp = async () => {
try {
await signUp({
email: 'user@example.com',
password: 'securePassword123',
display_name: 'John Doe' // optional
});
// User is automatically redirected
} catch (error) {
console.error('Sign up failed:', error);
}
};
}
import { useAuth } from '../contexts/AuthContext';
function SignInComponent() {
const { signIn } = useAuth();
const handleSignIn = async () => {
try {
await signIn({
email: 'user@example.com',
password: 'securePassword123'
});
// User is automatically redirected
} catch (error) {
console.error('Sign in failed:', error);
}
};
}
import { useAuth } from '../contexts/AuthContext';
function ProfileComponent() {
const { user, firebaseUser, loading } = useAuth();
if (loading) {
return <LoadingSpinner />;
}
return (
<View>
<Text>Email: {user?.email}</Text>
<Text>Name: {user?.display_name}</Text>
<Text>Tier: {user?.tier}</Text>
<Text>Firebase UID: {firebaseUser?.uid}</Text>
</View>
);
}
import { useAuth } from '../contexts/AuthContext';
function SignOutButton() {
const { signOut } = useAuth();
const handleSignOut = async () => {
try {
await signOut();
// User is automatically redirected to login
} catch (error) {
console.error('Sign out failed:', error);
}
};
return <Button onPress={handleSignOut}>Sign Out</Button>;
}
The app automatically protects routes using the auth state:
// app/index.tsx
export default function Index() {
const { user, loading } = useAuth();
if (loading) {
return <LoadingScreen />;
}
if (!user) {
return <Redirect href="/login" />;
}
return <Redirect href="/(tabs)" />;
}
users tablelast_login_at in Supabase.env.localThe system includes comprehensive error handling:
To test the authentication system:
.env.local with valid credentialsnpm start
/login.env.local has all Firebase credentials.env.local