Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Jason-AML/MonzaSport-Nextjs/llms.txt

Use this file to discover all available pages before exploring further.

Monza Motors uses Supabase for email and password authentication with server-side rendering (SSR) cookie-based session management via the @supabase/ssr package. This approach means the session is stored in an HTTP-only cookie and is available to both client components and Next.js server components or API routes — eliminating the need to pass auth tokens manually between layers.

Authentication Flow

1

Register at /register

The user fills in an email and password in RegisterForm. On submit, registerService() calls supabase.auth.signUp(). If the email is already registered, the response includes an empty identities array and the form surfaces an error toast rather than proceeding.
2

Sign in at /login

The user fills in their credentials in LoginForm. On submit, signIn() calls supabase.auth.signInWithPassword(). A successful sign-in shows a welcome toast and redirects to /.
3

Session stored in cookies

The Supabase SSR client automatically writes the access and refresh tokens to cookies on the response. Subsequent requests include these cookies, so the server can validate the session without an extra round trip to Supabase.
4

AuthProvider synchronises client state

AuthProvider wraps the entire app. It is initialised with the initialUser value resolved server-side, then subscribes to supabase.auth.onAuthStateChange to keep the React context in sync whenever the user signs in or out in any tab.
5

Server components read the session with getUser()

Any server component or API route can call getUser() from auth.server.js to retrieve the currently signed-in user without touching the client. If no valid session exists, getUser() returns null.

Client-side Functions

Three functions are exported from src/services/auth/auth.client.js. They all use the browser Supabase client initialised from the public anon key.
// Sign in with email and password
export async function signIn(email, password) {
  const { data, error } = await supabase.auth.signInWithPassword({ email, password });
  if (error) throw new Error(error.message);
  return data;
}

// Sign out the current user
export async function signOut() {
  const { error } = await supabase.auth.signOut();
  if (error) throw new Error(error.message);
}

// Register a new user
export const registerService = (email, password) => {
  return supabase.auth.signUp({ email, password });
};
signIn and signOut throw on error so callers can catch and display user-facing messages. registerService returns the raw Supabase response instead, which lets RegisterForm inspect data.user.identities to detect duplicate accounts before showing a success message.

Server-side User Retrieval

getUser() in src/services/auth/auth.server.js uses a server-only Supabase client created with @supabase/ssr’s cookie store. It validates the session against Supabase’s auth server and returns the user object, or null if the session is missing or invalid.
export const getUser = async () => {
  const supabase = await createClient();
  const {
    data: { user },
    error,
  } = await supabase.auth.getUser();
  if (error || !user) return null;
  return user;
};
This function is used in the checkout API route to gate purchases behind authentication, and can be called in any server component to personalise page content.

AuthProvider

AuthProvider is a client-side context provider defined in src/providers/AuthProvider.jsx. It accepts an initialUser prop (typically the result of getUser() called in the root layout server component) so the initial render never flickers — the user object is already populated before the first paint. After mounting, it subscribes to onAuthStateChange. Whenever the Supabase auth state changes (sign-in, sign-out, token refresh), the user state is updated and all consumers re-render automatically. The subscription is cleaned up on unmount. Consume the context anywhere in the component tree with the useAuth hook:
import { useAuth } from '@/providers/AuthProvider';

function MyComponent() {
  const { user, loading } = useAuth();
  // user is null when logged out
}
  • user — the Supabase User object, or null when not signed in.
  • loadingtrue during the initial auth state resolution; false once the state is known.

Route Protection

The POST /api/checkout route calls getUser() at the very start of the handler. If the call returns null, it immediately responds with HTTP 401 Unauthorized and does not create a Stripe session. On the client side, the Detail component’s handleStripe function checks for a 401 status and redirects the user to /error, prompting them to sign in before attempting to purchase.
SUPABASE_SERVICE_ROLE_KEY is only used server-side inside the /api/chat route, where it bypasses row-level security to read and write the messages table on behalf of any user. All authentication operations — sign-up, sign-in, sign-out, and session validation — use the public anon key (NEXT_PUBLIC_SUPABASE_ANON_KEY), which is safe to expose in the browser.

Build docs developers (and LLMs) love