Skip to main content

Overview

The useAuthStore is a Zustand-powered state management hook that handles authentication state, user data, and session lifecycle. It provides methods for initializing the session, logging in, and logging out.

Import

import { useAuthStore } from '@app/store/auth/auth.store'

Type Signature

type AuthStore = AuthState & {
  init: () => Promise<void>
  login: (user: User) => void
  logout: () => void
}

type AuthState = {
  isAuthenticated: boolean
  isOnboarded: boolean
  user: User | null
  initialized: boolean
}

type User = {
  id: number
  email: string
  role: 'ORGANIZER' | 'TEAM_ADMIN'
  is_onboarded: boolean
}

State Properties

isAuthenticated
boolean
Indicates whether the user is currently authenticated. true if a valid user session exists.
isOnboarded
boolean
Indicates whether the authenticated user has completed onboarding. Mirrors the user.is_onboarded value.
user
User | null
The authenticated user object, or null if not authenticated.User Properties:
  • id: Unique user identifier
  • email: User’s email address
  • role: Either 'ORGANIZER' or 'TEAM_ADMIN'
  • is_onboarded: Whether user completed onboarding
initialized
boolean
Indicates whether the store has completed initialization. Prevents redundant API calls on mount.

Methods

init()

Asynchronously initializes the authentication state by fetching the current user from the API.
init: () => Promise<void>
Behavior:
  • Checks if already initialized; returns early if true
  • Calls GET /auth/me to fetch current user
  • On success: sets user data and authentication flags
  • On failure: clears user data and sets authenticated to false
  • Always marks the store as initialized
Example:
import { useAuthStore } from '@app/store/auth/auth.store'
import { useEffect } from 'react'

function App() {
  const init = useAuthStore(state => state.init)

  useEffect(() => {
    init()
  }, [])

  return <YourApp />
}

login(user)

Sets the authentication state after successful login.
login: (user: User) => void
user
User
required
The authenticated user object containing:
  • id: User identifier
  • email: User’s email
  • role: User role ('ORGANIZER' or 'TEAM_ADMIN')
  • is_onboarded: Onboarding status
Example:
import { useAuthStore } from '@app/store/auth/auth.store'
import { apiPOST } from '@app/api/client'

async function handleLogin(email: string, password: string) {
  const login = useAuthStore.getState().login
  
  const user = await apiPOST('/auth/login', {
    body: JSON.stringify({ email, password })
  })
  
  login(user)
}

logout()

Clears the authentication state and user data.
logout: () => void
Behavior:
  • Sets user to null
  • Sets isAuthenticated to false
  • Sets isOnboarded to false
  • Keeps initialized as true
Example:
import { useAuthStore } from '@app/store/auth/auth.store'

function LogoutButton() {
  const logout = useAuthStore(state => state.logout)

  return (
    <button onClick={logout}>
      Sign Out
    </button>
  )
}

Usage Examples

Accessing Auth State in Components

import { useAuthStore } from '@app/store/auth/auth.store'

function UserProfile() {
  const { user, isAuthenticated } = useAuthStore()

  if (!isAuthenticated || !user) {
    return <div>Please log in</div>
  }

  return (
    <div>
      <h1>Welcome, {user.email}</h1>
      <p>Role: {user.role}</p>
      <p>Onboarded: {user.is_onboarded ? 'Yes' : 'No'}</p>
    </div>
  )
}

Optimized Selectors

import { useAuthStore } from '@app/store/auth/auth.store'

function UserEmail() {
  // Only re-renders when email changes
  const email = useAuthStore(state => state.user?.email)
  
  return <span>{email}</span>
}

Conditional Rendering by Role

import { useAuthStore } from '@app/store/auth/auth.store'

function AdminPanel() {
  const role = useAuthStore(state => state.user?.role)

  if (role !== 'TEAM_ADMIN') {
    return <div>Access denied</div>
  }

  return <div>Admin controls...</div>
}

Outside React Components

import { useAuthStore } from '@app/store/auth/auth.store'

// Access store outside components
function isUserAuthenticated(): boolean {
  return useAuthStore.getState().isAuthenticated
}

// Subscribe to changes
const unsubscribe = useAuthStore.subscribe(
  state => state.user,
  (user) => {
    console.log('User changed:', user)
  }
)

Integration with API Client

The store is integrated with the API client at src/app/api/client.ts. When a request returns a 401 Unauthorized status, the client automatically calls useAuthStore.getState().logout() to clear the session.

Initial State

{
  isAuthenticated: false,
  isOnboarded: false,
  user: null,
  initialized: false
}

Source

Implemented in: src/app/store/auth/auth.store.ts:11

Build docs developers (and LLMs) love