Authentication API
Authentication is handled by Supabase Auth. This page documents the auth flow and related endpoints.
Auth Flow
Y3NKO uses Supabase Auth with the following providers:
- Email/Password
- Google OAuth
- Magic Links
Sign Up
Email/Password
// Using Supabase client
import { createClient } from '@/lib/supabase/client'
const supabase = createClient()
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'securepassword',
options: {
data: {
first_name: 'Kwame',
last_name: 'Asante'
}
}
})Response
{
"user": {
"id": "uuid-here",
"email": "user@example.com",
"user_metadata": {
"first_name": "Kwame",
"last_name": "Asante"
}
},
"session": null // Email confirmation required
}Email confirmation is required. Users receive a confirmation email with a magic link.
Sign In
Email/Password
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'securepassword'
})Google OAuth
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})Magic Link
const { data, error } = await supabase.auth.signInWithOtp({
email: 'user@example.com',
options: {
emailRedirectTo: `${window.location.origin}/auth/callback`
}
})Auth Callback
Handle OAuth and magic link callbacks:
// app/auth/callback/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const code = searchParams.get('code')
const next = searchParams.get('next') ?? '/dashboard'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(new URL(next, request.url))
}
}
return NextResponse.redirect(new URL('/auth/error', request.url))
}Sign Out
const { error } = await supabase.auth.signOut()Get Current User
Client-side
const { data: { user } } = await supabase.auth.getUser()Server-side
// In Server Component or Server Action
import { createClient } from '@/lib/supabase/server'
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()Password Reset
Request Reset
const { data, error } = await supabase.auth.resetPasswordForEmail(
'user@example.com',
{
redirectTo: `${window.location.origin}/auth/reset-password`
}
)Update Password
const { data, error } = await supabase.auth.updateUser({
password: 'newSecurePassword'
})Session Management
Sessions are automatically managed via HTTP-only cookies.
Check Session
const { data: { session } } = await supabase.auth.getSession()Refresh Session
Sessions are automatically refreshed. For manual refresh:
const { data, error } = await supabase.auth.refreshSession()User Profile Sync
After Supabase auth, sync user data to the application database:
// lib/auth.ts
import { createClient } from '@/lib/supabase/server'
import { prisma } from '@/lib/db'
export async function getCurrentUser() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) return null
// Find or create user in our database
let dbUser = await prisma.user.findUnique({
where: { id: user.id },
include: { profile: true }
})
if (!dbUser) {
dbUser = await prisma.user.create({
data: {
id: user.id,
email: user.email!,
emailVerified: user.email_confirmed_at ? new Date() : null,
profile: {
create: {
firstName: user.user_metadata.first_name || '',
lastName: user.user_metadata.last_name || '',
avatarUrl: user.user_metadata.avatar_url
}
}
},
include: { profile: true }
})
}
return dbUser
}Protected Routes
Use middleware to protect routes:
// middleware.ts
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
const response = NextResponse.next()
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
response.cookies.set(name, value, options)
)
},
},
}
)
const { data: { user } } = await supabase.auth.getUser()
// Redirect unauthenticated users
const protectedPaths = ['/dashboard', '/host', '/admin']
const isProtected = protectedPaths.some(path =>
request.nextUrl.pathname.startsWith(path)
)
if (isProtected && !user) {
const loginUrl = new URL('/login', request.url)
loginUrl.searchParams.set('next', request.nextUrl.pathname)
return NextResponse.redirect(loginUrl)
}
return response
}
export const config = {
matcher: ['/dashboard/:path*', '/host/:path*', '/admin/:path*']
}Error Codes
| Code | Description |
|---|---|
invalid_credentials | Wrong email or password |
email_not_confirmed | Email not verified |
user_already_exists | Email already registered |
weak_password | Password doesn’t meet requirements |
over_email_send_rate_limit | Too many email requests |