Le Duy Khuong

Chuỗi: supabase-series · Phần 5

Năng suất & công cụ dev

Auth: JWT, session và tích hợp backend

Supabase Auth, JWT; verify JWT ở backend (NestJS, Express, FastAPI). Session và refresh. Secret chỉ server-side.

2026-03-173 phút đọcVI

Auth: JWT, session and backend integration

Introduction

Supabase Auth cung cấp đăng ký/đăng nhập (email, OAuth, magic link), quản lý session và phát JWT. Client gửi JWT trong header khi gọi PostgREST hoặc API riêng; backend cần verify JWT để biết user và áp dụng RLS hoặc logic nghiệp vụ. Bài này tóm tắt JWT của Supabase, session/refresh, và cách verify JWT ở backend (NestJS, Express, FastAPI, …).

Mục tiêu: Hiểu luồng auth (login → JWT → gửi kèm request), verify JWT an toàn ở server và nguyên tắc “secret chỉ server-side”.

Features

Supabase Auth

  • Providers: Email/password, OAuth (Google, GitHub, etc.), magic link. Configure in Dashboard → Authentication → Providers.
  • Session: After login the client receives access_token (JWT) and refresh_token; the access_token is sent with each request (header Authorization: Bearer <token>).
  • JWT: Contains claims (sub = user id, email, role, etc.); signed with the project JWT secret. PostgREST uses the JWT to set auth.uid() in RLS; your own backend verifies with the same secret to get the user id.

Refresh

  • Access token has a short lifetime (e.g. 1 hour); the refresh token is used to get a new access token without logging in again. The Supabase JS client refreshes automatically when calling getSession() or when the token is about to expire (depending on config).

Workflow / process

  1. Configure Auth (Dashboard): Enable providers, redirect URL; (optional) customize JWT expiry.
  2. Client login: supabase.auth.signInWithPassword() or OAuth → receive session (access_token, refresh_token).
  3. Client sends request: Send header Authorization: Bearer <access_token> to PostgREST or your backend API.
  4. PostgREST: Verifies JWT (using project JWT secret), sets request.jwt.claims; RLS uses auth.uid() = sub.
  5. Your backend: Verify JWT with the secret (from env), extract sub (user id); do not log the token or send it outside.

Convention: JWT secret exists only on the server; the client keeps the access_token in memory (or secure storage) and sends it with requests; never send refresh_token or secret to third parties.

Sample code

Client: đăng nhập và gửi request

const { data, error } = await supabase.auth.signInWithPassword({ email, password });
if (data?.session) {
  // Gửi API kèm token
  const token = data.session.access_token;
  const res = await fetch('/api/me', {
    headers: { Authorization: `Bearer ${token}` },
  });
}

Backend (Node/Express): verify JWT với secret

const jwt = require('jsonwebtoken');
 
function getUserIdFromRequest(req) {
  const authHeader = req.headers.authorization;
  const token = authHeader?.replace(/^Bearer\s+/i, '');
  if (!token) return null;
  try {
    const secret = process.env.SUPABASE_JWT_SECRET; // từ Dashboard → Settings → API
    const decoded = jwt.verify(token, secret);
    return decoded.sub; // user id
  } catch {
    return null;
  }
}
// Không log token hoặc secret.

Backend (NestJS): guard dùng Passport JWT

// Dùng @nestjs/passport passport-jwt; strategy verify với same secret, extract sub.
// Guard gắn user id vào request; controller dùng request.user.id.

Apply in your architecture

  • Auth at edge / server: Authentication happens on the server (PostgREST or backend); the client only carries the token. Never expose JWT secret or service role key to the client.
  • Secrets server-side only: JWT secret and service role key are read only from env on the server; never logged or returned in responses. The client only needs the anon key (public) and access token (short-lived).
  • One identity for many channels: The same JWT is used for PostgREST (RLS) and your backend API; both rely on the same user id for consistent permissions.

Summary

Supabase Auth issues a JWT after login; the client sends a Bearer token; PostgREST and your backend verify it with the JWT secret. Next: Prisma connecting to Supabase and syncing schema.

Next: 06 — Prisma + Supabase

Further reading: Supabase Auth — JWT

LDK

Le Duy Khuong

AI Transformation & Digital Strategy. Writing about agentic systems, engineering leadership, and building in public.