OnlyAutomator’s authentication system is built on Supabase Auth, providing secure and flexible user authentication with multiple sign-in methods.

Authentication Flow

The system supports a seamless authentication process for users:
  • Multiple Sign-in Methods: Email/password, Google OAuth, and magic links
  • Secure Password Management: Hashed storage and robust password policies
  • Session Management: Token-based authentication with configurable expiration
  • Email Verification: Automated verification for new email accounts
  • Password Recovery: Self-service password reset functionality
Authentication flow with Supabase

Authentication Methods

Email Authentication

Standard email and password authentication with security features:
// Sign up with email/password
const signUp = async (email: string, password: string) => {
  try {
    const { data, error } = await supabase.auth.signUp({
      email,
      password,
    });
    
    if (error) throw error;
    return data;
  } catch (error) {
    console.error('Error signing up:', error);
    throw error;
  }
};

// Sign in with email/password
const signIn = async (email: string, password: string) => {
  try {
    const { data, error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });
    
    if (error) throw error;
    return data;
  } catch (error) {
    console.error('Error signing in:', error);
    throw error;
  }
};

OAuth Authentication

Integration with Google OAuth for simplified sign-in:
// Sign in with Google
const signInWithGoogle = async () => {
  try {
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider: 'google',
      options: {
        redirectTo: `${window.location.origin}/auth/callback`,
      },
    });
    
    if (error) throw error;
    return data;
  } catch (error) {
    console.error('Error signing in with Google:', error);
    throw error;
  }
};
Passwordless authentication via email magic links:
// Sign in with magic link
const signInWithMagicLink = async (email: string) => {
  try {
    const { data, error } = await supabase.auth.signInWithOtp({
      email,
      options: {
        emailRedirectTo: `${window.location.origin}/auth/callback`,
      },
    });
    
    if (error) throw error;
    return data;
  } catch (error) {
    console.error('Error sending magic link:', error);
    throw error;
  }
};

Session Management

OnlyAutomator handles user sessions through Supabase’s session API:
// Get current session
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);
    return null;
  }
};

// Sign out
const signOut = async () => {
  try {
    const { error } = await supabase.auth.signOut();
    
    if (error) throw error;
  } catch (error) {
    console.error('Error signing out:', error);
    throw error;
  }
};

User Profile Management

The authentication system also handles user profile data:
// Get user profile data
const getUserProfile = async (userId: string) => {
  try {
    const { data, error } = await supabase
      .from('profiles')
      .select('*')
      .eq('id', userId)
      .single();
    
    if (error) throw error;
    return data;
  } catch (error) {
    console.error('Error fetching user profile:', error);
    throw error;
  }
};

// Update user profile
const updateUserProfile = async (userId: string, updates: Partial<Profile>) => {
  try {
    const { data, error } = await supabase
      .from('profiles')
      .update(updates)
      .eq('id', userId)
      .select()
      .single();
    
    if (error) throw error;
    return data;
  } catch (error) {
    console.error('Error updating user profile:', error);
    throw error;
  }
};

Row-Level Security (RLS)

Supabase provides Row-Level Security for data protection:
-- Example RLS policy for the profiles table
CREATE POLICY "Users can view their own profile"
ON profiles
FOR SELECT
USING (auth.uid() = id);

CREATE POLICY "Users can update their own profile"
ON profiles
FOR UPDATE
USING (auth.uid() = id);

Authentication Context

A React Context provides authentication state throughout the application:
// Auth context definition
import { createContext, useContext, useEffect, useState } from 'react';
import { User, Session } from '@supabase/supabase-js';
import { supabase } from '@/lib/supabase';

interface AuthContextType {
  user: User | null;
  session: Session | null;
  loading: boolean;
  signUp: (email: string, password: string) => Promise<any>;
  signIn: (email: string, password: string) => Promise<any>;
  signInWithGoogle: () => Promise<any>;
  signInWithMagicLink: (email: string) => Promise<any>;
  signOut: () => Promise<void>;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [session, setSession] = useState<Session | null>(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    // Get initial session
    supabase.auth.getSession().then(({ data: { session } }) => {
      setSession(session);
      setUser(session?.user ?? null);
      setLoading(false);
    });
    
    // Listen for auth changes
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      (_event, session) => {
        setSession(session);
        setUser(session?.user ?? null);
        setLoading(false);
      }
    );
    
    return () => subscription.unsubscribe();
  }, []);
  
  const value = {
    user,
    session,
    loading,
    signUp: (email: string, password: string) => 
      supabase.auth.signUp({ email, password }),
    signIn: (email: string, password: string) => 
      supabase.auth.signInWithPassword({ email, password }),
    signInWithGoogle: () => 
      supabase.auth.signInWithOAuth({ 
        provider: 'google',
        options: { redirectTo: `${window.location.origin}/auth/callback` }
      }),
    signInWithMagicLink: (email: string) => 
      supabase.auth.signInWithOtp({
        email,
        options: { emailRedirectTo: `${window.location.origin}/auth/callback` }
      }),
    signOut: () => supabase.auth.signOut(),
  };
  
  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};

Protected Routes

Routes can be protected based on authentication status:
// Protected route component
import { useRouter } from 'next/router';
import { useAuth } from '@/lib/auth';

export function ProtectedRoute({ children }: { children: React.ReactNode }) {
  const { user, loading } = useAuth();
  const router = useRouter();
  
  useEffect(() => {
    if (!loading && !user) {
      router.push('/login');
    }
  }, [user, loading, router]);
  
  if (loading) {
    return <div>Loading...</div>;
  }
  
  return user ? <>{children}</> : null;
}

User Roles and Permissions

OnlyAutomator implements role-based access control through Supabase:
-- User roles in the database
CREATE TABLE user_roles (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
  role TEXT NOT NULL CHECK (role IN ('admin', 'user', 'creator')),
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(user_id, role)
);

-- Function to check if a user has a specific role
CREATE OR REPLACE FUNCTION public.user_has_role(user_id UUID, role_name TEXT)
RETURNS BOOLEAN AS $$
  SELECT EXISTS (
    SELECT 1
    FROM user_roles
    WHERE user_id = $1 AND role = $2
  );
$$ LANGUAGE sql SECURITY DEFINER;

Configuration

The authentication system is configured through environment variables:
# Supabase authentication settings
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

# OAuth settings (for Google integration)
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-google-client-id
NEXT_PUBLIC_GOOGLE_CLIENT_SECRET=your-google-client-secret
NEXT_PUBLIC_SUPABASE_AUTH_URL=https://your-project.supabase.co/auth/v1/callback

Security Considerations

The authentication system follows security best practices:
  • HTTPS Only: All authentication traffic is encrypted
  • JWT Validation: Proper validation of JSON Web Tokens
  • CORS Configuration: Restricts cross-origin requests
  • Rate Limiting: Protection against brute-force attacks
  • Session Expiration: Automatic expiry of inactive sessions
  • Secure Cookies: HTTP-only cookies for session management