Hands‑On: Integrating an Authorization System

Vibe Prompt

“Help me build a full‑stack authorization system with Supabase and Next.js: Google login, RBAC permissions, and middleware protection.”

Full Example

Below is a minimal yet complete implementation that demonstrates how to combine Google OAuth, Role‑Based Access Control (RBAC), JWT for stateless API calls, and Supabase sessions in a Next.js application. The example uses the new app router and middleware features introduced in Next.js 13.

// middleware.ts
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs';
import { NextResponse } from 'next/server';

// Routes that require a logged‑in user
const protectedRoutes = ['/dashboard', '/courses/*'];
// Routes that require an admin role
const adminRoutes = ['/admin', '/admin/*'];

export async function middleware(req) {
  const res = NextResponse.next();
  const supabase = createMiddlewareClient({ req, res });

  // Retrieve the current session (JWT + refresh token)
  const { data: { session } } = await supabase.auth.getSession();

  const path = req.nextUrl.pathname;

  // 1️⃣ Protect routes that need authentication
  if (protectedRoutes.some(p => path.match(p))) {
    if (!session) {
      // Redirect to login if no session
      return NextResponse.redirect(new URL('/login', req.url));
    }
  }

  // 2️⃣ Protect admin routes
  if (adminRoutes.some(p => path.match(p))) {
    const { data: { user } } = await supabase.auth.getUser();
    const role = user?.user_metadata?.role;
    if (role !== 'admin') {
      // Non‑admin users are redirected to the dashboard
      return NextResponse.redirect(new URL('/dashboard', req.url));
    }
  }

  return res;
}
// app/dashboard/page.tsx
import { createServerClient } from '@/utils/supabase/server';

export default async function DashboardPage() {
  const supabase = createServerClient();
  const { data: { user } } = await supabase.auth.getUser();

  // Retrieve the role from user_metadata
  const role = user?.user_metadata?.role ?? 'viewer';

  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {user?.email}</p>
      <p>Role: {role}</p>

      {role === 'admin' && <AdminPanel />}
      {role === 'editor' && <EditorPanel />}
      {/* Viewer gets only read‑only UI */}
    </div>
  );
}

Why this matters
A single, well‑structured authorization layer eliminates duplicated logic, reduces the attack surface, and gives developers a clear contract for who can do what. In a commercial product, this translates to faster feature rollout, fewer security incidents, and compliance with regulations such as GDPR or HIPAA.

Course Summary

You have just completed the IAM (Identity & Access Management) module. Here’s what you can now confidently build:

| ✅ | Topic | |---|-------| | ✅ | OAuth 2.0 / OIDC | | ✅ | RBAC / ABAC | | ✅ | Session Management | | ✅ | PKCE flow for native & SPA apps | | ✅ | End‑to‑end Authorization System |

Key Takeaways

  • Authentication vs. Authorization – Authentication verifies who you are; authorization determines what you can do.
  • Supabase Auth – Handles password, social, and magic link flows out of the box.
  • JWT – Stateless tokens ideal for API calls; keep them short‑lived and signed.
  • Supabase Sessions – Persisted in the database; useful for server‑side rendering and session revocation.
  • RBAC – Store roles in user_metadata or a separate roles table; enforce in middleware and Row‑Level Security (RLS).
  • Middleware – Central place to guard routes before they hit the server.
  • Security best practices – Rotate secrets, use HTTPS, implement rate limiting, and enable CORS.

Detailed Integration Flow

Below is a step‑by‑step guide that walks through every layer of a production‑ready authorization stack.

1️⃣ Authentication Layer

| Feature | What | Why | How | |---------|------|-----|-----| | Password login | Bcrypt hashed passwords | Protect user credentials | Use Supabase’s signUp / signIn | | Social login | Google, LINE, GitHub | Reduce friction | Configure OAuth providers in Supabase dashboard | | MFA / TOTP | Time‑based one‑time passwords | Add a second factor | Use supabase.auth.mfa or third‑party libraries | | PKCE | Proof Key for Code Exchange | Secure public clients | Supabase handles PKCE automatically for SPA |

Implementation tip – Store the user’s role in user_metadata during signup or via a serverless function after the OAuth callback.

2️⃣ Session Layer

| Token | What | Why | How | |-------|------|-----|-----| | Session token | Stored in Supabase DB | Revocable, server‑side | supabase.auth.getSession() | | JWT | Stateless, signed | Fast API auth | supabase.auth.getUser() returns decoded JWT |

Best practice – Keep JWT expiry short (e.g., 15 min) and use refresh tokens for longer sessions.

3️⃣ Authorization Layer

| Model | What | Why | How | |-------|------|-----|-----| | RBAC | Role → Permissions | Simple, scalable | Store roles in user_metadata or a roles table | | ABAC | Attribute → Policy | Fine‑grained | Use Supabase RLS with custom policies | | Middleware | Route guard | Centralized logic | createMiddlewareClient + NextResponse redirects | | RLS | Row‑level security | Database‑level enforcement | ALTER TABLE ... ENABLE ROW LEVEL SECURITY |

Example – An admin role can access /admin/*; an editor can edit courses but not delete them.

4️⃣ API Layer

| Feature | What | Why | How | |---------|------|-----|-----| | Rate limiting | Throttle requests | Prevent abuse | Use Vercel Edge Functions or Cloudflare Workers | | CORS | Cross‑origin policies | Browser security | Configure in next.config.js or Supabase | | Validation | Input sanitization | Avoid injection | Use zod or yup schemas |

5️⃣ Data Layer

| Feature | What | Why | How | |---------|------|-----|-----| | RLS | Row‑level security | Enforce policies at DB | CREATE POLICY statements | | Encryption | Column‑level | Protect sensitive data | Supabase supports pgcrypto or pgcrypto functions |

Expanded Example: Role Assignment After Google OAuth

// utils/supabase/server.ts
import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
);

// After Google login, assign role
export async function assignRole(userId: string, role: string) {
  const { error } = await supabase
    .from('users')
    .update({ role })
    .eq('id', userId);

  if (error) throw error;
}
// pages/api/auth/callback/google.ts
import { assignRole } from '@/utils/supabase/server';

export default async function handler(req, res) {
  const { user } = await supabase.auth.getUser();

  // Default role for new users
  await assignRole(user.id, 'viewer');

  res.redirect('/dashboard');
}

Why – By storing the role in a dedicated column, you can query it efficiently and keep the user_metadata lightweight.

Security Checklist

| Item | Description | Implementation | |------|-------------|----------------| | HTTPS | Encrypt traffic | Vercel automatically provides HTTPS | | Secret rotation | Rotate API keys | Use GitHub Actions secrets | | CSRF protection | Prevent cross‑site requests | Supabase auth includes anti‑CSRF tokens | | Input validation | Avoid injection | Use zod schemas in API routes | | Logging | Audit trails | Log role changes, failed logins |

Performance Considerations

  • Cache user roles in Redis or in‑memory for high‑traffic routes.
  • Use Supabase Edge Functions to offload heavy computations.
  • Batch database queries when fetching multiple resources.

Testing Strategy

  1. Unit tests – Verify role assignment logic.
  2. Integration tests – Use Cypress to simulate login flows.
  3. Security tests – Run OWASP ZAP or similar scanners.
  4. Load tests – Use k6 to ensure middleware scales.

Deployment Tips

  • Environment variables – Store SUPABASE_SERVICE_ROLE_KEY in Vercel’s secrets.
  • Edge middleware – Deploy on Vercel Edge Network for low latency.
  • Database backups – Enable automated backups in Supabase.

Transition to the Next Chapter

You now possess a fully functional, secure, and scalable authorization system that ties together authentication, session management, RBAC, and database‑level security. In the next chapter, we will explore multi‑tenant architecture and fine‑grained access control using ABAC and policy engines. We’ll learn how to model tenant boundaries, enforce isolation, and dynamically evaluate complex policies at runtime. This knowledge will empower you to build SaaS products that can safely serve multiple customers while maintaining strict data segregation and compliance. If this is the final chapter, congratulations! You’ve mastered IAM from the ground up. The next step is to apply these skills to real‑world commercial projects: design a product roadmap, integrate with CI/CD pipelines, monitor security metrics, and continuously iterate on your authorization logic to meet evolving business requirements.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!