Authentication
NaijaBase Auth handles user sign-up, sign-in, session management, and JWT issuance. It integrates directly with Row Level Security so your database policies automatically enforce access control based on the authenticated user.
Quick start
import { createClient } from '@naijabase/js'
const nb = createClient(
process.env.NEXT_PUBLIC_NAIJABASE_URL,
process.env.NEXT_PUBLIC_NAIJABASE_ANON_KEY
)
Sign up
const { data, error } = await nb.auth.signUp({
email: 'ada@example.ng',
password: 'securepassword',
})
if (error) {
console.error('Sign-up failed:', error.message)
} else {
console.log('User created:', data.user.id)
}
By default, new users must verify their email before they can sign in. You can disable this in your project settings.
Sign in
const { data, error } = await nb.auth.signInWithPassword({
email: 'ada@example.ng',
password: 'securepassword',
})
if (error) {
console.error('Sign-in failed:', error.message)
} else {
console.log('Session:', data.session.access_token)
}
Get the current user
const { data: { user }, error } = await nb.auth.getUser()
if (user) {
console.log('Logged in as:', user.email)
} else {
console.log('Not authenticated')
}
Get the current session
const { data: { session } } = await nb.auth.getSession()
if (session) {
console.log('Access token expires at:', session.expires_at)
}
Sign out
const { error } = await nb.auth.signOut()
Listen for auth state changes
const { data: { subscription } } = nb.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') {
console.log('Signed in:', session.user.email)
}
if (event === 'SIGNED_OUT') {
console.log('Signed out')
}
})
// Later: unsubscribe
subscription.unsubscribe()
Password reset
// Step 1: Send reset email
await nb.auth.resetPasswordForEmail('ada@example.ng', {
redirectTo: 'https://yourapp.com/reset-password',
})
// Step 2: Update password (after user clicks email link)
await nb.auth.updateUser({ password: 'newpassword' })
Update user metadata
await nb.auth.updateUser({
data: { full_name: 'Adaeze Okonkwo', avatar_url: 'https://...' },
})
Using auth with Row Level Security
Every authenticated request carries the user's JWT. NaijaBase extracts sub (the user's UUID) and exposes it as auth.uid() inside PostgreSQL policies.
-- Only let users read their own profile
CREATE POLICY "own profile"
ON profiles
FOR SELECT
USING (user_id = auth.uid());
The auth.uid() function returns the UUID from the JWT's sub claim, matching the id column in the auth.users table.
REST API (curl)
Sign up
curl -X POST https://api.naijabase.dev/auth/v1/signup \
-H "Content-Type: application/json" \
-H "apikey: nb_anon_..." \
-d '{"email": "ada@example.ng", "password": "securepassword"}'
Sign in
curl -X POST https://api.naijabase.dev/auth/v1/token?grant_type=password \
-H "Content-Type: application/json" \
-H "apikey: nb_anon_..." \
-d '{"email": "ada@example.ng", "password": "securepassword"}'
Response:
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "...",
"user": { "id": "uuid", "email": "ada@example.ng" }
}
Get user (with JWT)
curl https://api.naijabase.dev/auth/v1/user \
-H "apikey: nb_anon_..." \
-H "Authorization: Bearer eyJ..."
Sign out
curl -X POST https://api.naijabase.dev/auth/v1/logout \
-H "apikey: nb_anon_..." \
-H "Authorization: Bearer eyJ..."
JWT structure
NaijaBase issues standard HS256 JWTs. The payload includes:
{
"sub": "user-uuid",
"email": "ada@example.ng",
"role": "authenticated",
"iat": 1234567890,
"exp": 1234571490
}
The role claim is used by the REST API to set the PostgreSQL role before executing queries, enabling RLS.
Server-side auth (Next.js)
Never trust the client for auth on the server. Use getUser() — it verifies the JWT signature against NaijaBase:
// app/api/protected/route.js
import { createClient } from '@naijabase/js'
export async function GET(req) {
const token = req.headers.get('authorization')?.replace('Bearer ', '')
const nb = createClient(process.env.NAIJABASE_URL, process.env.NAIJABASE_SERVICE_KEY)
const { data: { user }, error } = await nb.auth.getUser(token)
if (error || !user) return new Response('Unauthorized', { status: 401 })
return Response.json({ userId: user.id })
}
Security notes
- Use
NEXT_PUBLIC_NAIJABASE_ANON_KEYin browser code — it's safe to expose. - Never expose
NAIJABASE_SERVICE_KEYin browser code. The service key bypasses RLS and must stay server-side only. - Access tokens expire in 1 hour. The SDK automatically refreshes them using the refresh token.
- Enable email verification in production to prevent fake accounts.