Skip to main content
The AuthContext provides centralized authentication state management for BoxApp. It handles user sessions, profiles, authentication methods, and role-based access control.

Provider Setup

Wrap your application with AuthProvider to enable authentication throughout your component tree.
import { AuthProvider } from '@/contexts/AuthContext';

function App() {
  return (
    <AuthProvider tenantBoxId="box-123">
      {/* Your app components */}
    </AuthProvider>
  );
}
tenantBoxId
string
Optional box ID for multi-tenant context. When provided, new user registrations and OAuth flows will automatically associate users with this box.

Hook Usage

Access the authentication context using the useAuth hook.
import { useAuth } from '@/contexts/AuthContext';

function MyComponent() {
  const { user, userProfile, isAdmin, signIn, signOut } = useAuth();
  
  if (!user) {
    return <div>Please sign in</div>;
  }
  
  return (
    <div>
      <h1>Welcome, {userProfile?.full_name}</h1>
      {isAdmin && <AdminPanel />}
      <button onClick={signOut}>Sign Out</button>
    </div>
  );
}
The useAuth hook must be used within an AuthProvider. An error will be thrown if used outside the provider tree.

State Properties

The context exposes the following state properties:
session
Session | null
The current Supabase session object. Contains tokens, user data, and session metadata.
user
User | null
The authenticated Supabase user object. Contains user ID, email, and metadata.
userProfile
Profile | null
The user’s profile data from the profiles table.
currentBox
Box | null
The box (gym) settings associated with the user’s profile. Automatically loaded when the user profile contains a box_id.
loading
boolean
Indicates whether authentication state is being initialized or updated. Use this to show loading states during sign-in, sign-up, or profile refresh operations.

Role-Based Flags

Convenience boolean flags for role-based access control:
isAdmin
boolean
Returns true if the user’s role_id is 'admin'.
isCoach
boolean
Returns true if the user’s role_id is 'coach'.
isAthlete
boolean
Returns true if the user’s role_id is 'athlete'.
isRoot
boolean
Returns true if the user’s email is '[email protected]' or user_metadata.is_root is true. Used for super-admin access.

Authentication Methods

signIn

Sign in a user with email and password.
const { signIn } = useAuth();

const handleSignIn = async () => {
  const { error, data } = await signIn({
    email: '[email protected]',
    password: 'securePassword123'
  });
  
  if (error) {
    console.error('Sign in failed:', error.message);
  }
};
credentials
object
required
Authentication credentials object.
Returns: Promise<{ error: any; data?: any }>

signInWithGoogle

Initiate Google OAuth sign-in flow.
const { signInWithGoogle } = useAuth();

const handleGoogleSignIn = async () => {
  const { error } = await signInWithGoogle('box-123');
  
  if (error) {
    console.error('Google sign in failed:', error.message);
  }
  // User will be redirected to Google OAuth flow
};
boxId
string
Optional box ID to associate with the user after OAuth completion. Stored in localStorage as pending_box_id and reconciled after redirect.
Returns: Promise<{ error: any }>
The OAuth flow redirects to /auth/callback. The onAuthStateChange listener handles session and profile fetch after redirect.

signUp

Register a new user account.
const { signUp } = useAuth();

const handleSignUp = async () => {
  const { data, error } = await signUp({
    email: '[email protected]',
    password: 'securePassword123',
    options: {
      data: {
        full_name: 'John Doe'
      }
    }
  });
  
  if (error) {
    console.error('Sign up failed:', error.message);
  }
};
credentials
object
required
User registration credentials.
Returns: Promise<{ data: any; error: any }>
If tenantBoxId was provided to the AuthProvider, it will automatically be injected into options.data.box_id during registration.

resetPassword

Send a password reset email to the user.
const { resetPassword } = useAuth();

const handlePasswordReset = async () => {
  const { error } = await resetPassword('[email protected]');
  
  if (error) {
    console.error('Password reset failed:', error.message);
  } else {
    console.log('Password reset email sent');
  }
};
email
string
required
Email address to send the password reset link to.
Returns: Promise<{ error: any }>
The reset link redirects to /reset-password on your application domain.

updateUser

Update the current user’s attributes.
const { updateUser } = useAuth();

const handleUpdateEmail = async () => {
  const { data, error } = await updateUser({
    email: '[email protected]'
  });
  
  if (error) {
    console.error('Update failed:', error.message);
  }
};
attributes
object
required
User attributes to update (e.g., email, password, data).
Returns: Promise<{ data: any; error: any }>

signOut

Sign out the current user and clear session state.
const { signOut } = useAuth();

const handleSignOut = async () => {
  await signOut();
  // User session cleared, state reset via onAuthStateChange
};
Returns: Promise<void>

refreshProfile

Manually refresh the user’s profile and box data from the database.
const { refreshProfile } = useAuth();

const handleProfileUpdate = async () => {
  // After updating profile in database
  await refreshProfile();
  // userProfile and currentBox are now up-to-date
};
Returns: Promise<void>

setCurrentBox

Manually set the current box in context.
const { setCurrentBox } = useAuth();

const handleBoxSwitch = (newBox: Box) => {
  setCurrentBox(newBox);
};
box
Box | null
required
The box object to set as current, or null to clear.

Multi-Tenant Behavior

The AuthContext includes built-in support for multi-tenant architecture:
  1. OAuth Box Association: When signInWithGoogle is called with a boxId (or tenantBoxId is available), the box ID is stored in localStorage as pending_box_id and reconciled after OAuth redirect.
  2. Profile Box Reconciliation: If a user’s profile lacks a box_id but the provider has a tenantBoxId, the profile is automatically updated with the correct box association.
  3. Sign-Up Box Injection: During registration, if tenantBoxId is provided to the provider, it’s automatically added to the user’s metadata.

TypeScript Types

interface AuthContextType {
  session: Session | null;
  user: User | null;
  userProfile: Profile | null;
  currentBox: Box | null;
  loading: boolean;
  isAdmin: boolean;
  isCoach: boolean;
  isRoot: boolean;
  isAthlete: boolean;
  signIn: (credentials: any) => Promise<{ error: any; data?: any }>;
  signInWithGoogle: (boxId?: string) => Promise<{ error: any }>;
  signUp: (credentials: any) => Promise<{ data: any; error: any }>;
  resetPassword: (email: string) => Promise<{ error: any }>;
  updateUser: (attributes: any) => Promise<{ data: any; error: any }>;
  signOut: () => Promise<void>;
  refreshProfile: () => Promise<void>;
  setCurrentBox: (box: Box | null) => void;
}

Implementation Details

Build docs developers (and LLMs) love