# Supabase Auth

> Supabase Auth + RLS + Middleware setup. Client/server helpers, middleware, RLS policies, and role-based access (user/teacher/admin). Use when adding authentication to a Next.js + Supabase project.

- Skill: `koach08/supabase-auth` (Agent Skill)
- Install (CLI): `npx skillmds@latest add koach08/supabase-auth`
- Raw SKILL.md: https://api.skillmd.com/api/skills/koach08/supabase-auth/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: koach08 (https://skillmd.com/u/koach08)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/koach08/supabase-auth

---


# Supabase Auth — Authentication Setup

Add authentication to a Next.js + Supabase project.

---

## Interview

- **Roles**: user only / user + teacher / user + teacher + admin
- **Registration method**: Email+password / Magic Link / OAuth (Google, etc.)
- **Teacher code**: Require a code for teacher registration?
- **Email confirmation**: Required / Not required (recommend OFF during development)

---

## What Gets Built

### 1. Supabase Client Helpers

```
src/lib/supabase/
├── client.ts    # Browser client (createBrowserClient)
├── server.ts    # Server Component / Route Handler
└── middleware.ts # Middleware client
```

### 2. Middleware

```
src/middleware.ts
```

- Refresh auth sessions
- Redirect unauthenticated users (to `/login`)
- Define public routes (`/`, `/login`, `/signup`, `/api/webhook`, etc.)

### 3. Auth Pages

```
src/app/(auth)/
├── login/page.tsx    # Login (email + password)
├── signup/page.tsx   # Registration (with role selection)
└── callback/route.ts # OAuth / Magic Link callback
```

### 4. Profile Table + RLS

```sql
create table profiles (
  id uuid primary key references auth.users(id) on delete cascade,
  role text default 'user' check (role in ('user', 'teacher', 'admin')),
  display_name text,
  created_at timestamptz default now()
);

alter table profiles enable row level security;

-- View and update own profile only
create policy "Users can view own profile"
  on profiles for select using (auth.uid() = id);
create policy "Users can update own profile"
  on profiles for update using (auth.uid() = id);

-- Auto-create on registration (trigger)
create or replace function public.handle_new_user()
returns trigger as $$
begin
  insert into public.profiles (id, role, display_name)
  values (new.id, 'user', new.raw_user_meta_data->>'display_name');
  return new;
end;
$$ language plpgsql security definer;

create trigger on_auth_user_created
  after insert on auth.users
  for each row execute function public.handle_new_user();
```

### 5. Supabase Dashboard Settings

- Site URL: Your production URL
- Redirect URLs: `http://localhost:3000/**`, `https://{domain}/**`
- Email confirmation: Recommend OFF during development
- Email templates: Customize as needed

---

## Role-Based Access Pattern

```typescript
// Check role on the server side
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
const { data: profile } = await supabase
  .from('profiles')
  .select('role')
  .eq('id', user.id)
  .single()

if (profile.role !== 'teacher') redirect('/dashboard')
```

