▸ Authentication Guide · 2025

SaaS Authentication Systems

TL;DR

A production SaaS authentication system combines email/password and OAuth providers for login, JWT tokens in httpOnly cookies for sessions, and role-based access control (RBAC) enforced at the database, API, and UI layers simultaneously. Auth is the security foundation of the entire product — it must be designed before any feature is built.

4Byte Agency uses Supabase Auth across all 45+ SaaS products — it handles JWT management, OAuth, magic links, and MFA out of the box, eliminating weeks of custom auth infrastructure.

Read time:18 min
Level:Technical
Focus:Security & Auth
By:4Byte Agency

▸ Authentication Methods

Four auth methods for SaaS — which ones to ship and when

Not every auth method is appropriate at every stage. Here are the four primary methods — with honest pros, cons, and a clear recommendation for each.

📧

Email & Password

Always — this is the minimum viable auth method for any SaaS product.

Required

The baseline authentication method. Users register with an email address and password. Requires email verification, secure password storage (bcrypt), and a password reset flow.

Advantages

  • Universal — every user knows how to use it
  • No dependency on third-party OAuth provider uptime
  • Full control over the credential lifecycle

Trade-offs

  • Users must remember another password
  • Higher support overhead for password resets
  • Requires email verification flow
🔗

OAuth Providers

Ship Google OAuth at minimum alongside email/password. GitHub OAuth for developer-facing products. LinkedIn for B2B sales tools.

Recommended

Users authenticate via a trusted third-party identity provider — Google, GitHub, LinkedIn, Microsoft. The provider handles credential management; you receive a verified identity token.

Advantages

  • No password management for users
  • Verified email from provider
  • Higher signup conversion rates
  • Provider handles MFA and security

Trade-offs

  • Dependency on provider availability
  • Users may have multiple identities across providers
  • Account linking complexity when same email exists

Magic Links

Excellent for low-friction B2B signups and internal tools where users accept email-based workflows.

Recommended

Passwordless authentication via a time-limited, single-use link sent to the user's email. The user clicks the link and is authenticated without a password.

Advantages

  • Zero password management
  • High conversion for new signups
  • No brute-force attack surface
  • Verified email implicit in flow

Trade-offs

  • Dependent on email deliverability
  • Users must access email to log in
  • Not suitable for environments without reliable email
🏢

SSO (SAML / Enterprise)

Required for enterprise-tier SaaS plans. Mid-market buyers frequently list SSO as a purchasing requirement.

Enterprise tier

Single Sign-On for enterprise buyers who manage identity centrally via an Identity Provider (IdP) like Okta, Azure AD, or Google Workspace. SAML 2.0 or OIDC protocol.

Advantages

  • Required by IT departments of mid-market+ buyers
  • Centralised user lifecycle management
  • Automatic deprovisioning when employees leave

Trade-offs

  • High implementation complexity
  • Requires SAML or OIDC integration per provider
  • Not necessary for self-serve SaaS MVPs

▸ JWT vs Sessions

JWT vs session-based auth — the definitive comparison

The JWT vs session debate is one of the most common questions in SaaS auth design. Here's the honest trade-off analysis for each dimension that matters.

Dimension
JWT (Stateless)
Session (Stateful)
Better For SaaS
Storage
Stored in httpOnly cookie or memory. Never localStorage.
Session ID in cookie; session data in server memory or Redis.
JWT
Statelessness
Fully stateless — the server validates the token signature without a database lookup.
Stateful — every request requires a session store lookup.
JWT
Revocation
Cannot be revoked before expiry without a token denylist (adds statefulness).
Immediate — delete the session record from the store.
Session
Scalability
Scales horizontally with zero shared state — any server can validate any token.
Requires a shared session store (Redis) for horizontal scaling.
JWT
RLS Integration
Integrates natively with Supabase RLS — auth.uid() reads directly from the JWT.
Requires custom RLS integration — must pass user ID explicitly.
JWT
Security
Secure when using httpOnly cookies and short expiry (15–60 min) with refresh tokens.
Secure with proper session store hardening and rotation on privilege changes.
Tie

4Byte verdict: Use JWT with Supabase Auth for all Next.js SaaS products. The statelessness advantage for serverless and Edge deployments, combined with native Supabase RLS integration via auth.uid(), makes JWT the clear choice. Use short expiry (1 hour) with refresh tokens stored in httpOnly cookies for security.

▸ Role-Based Access Control

The three-role RBAC model that works for 95% of SaaS products

Start with three roles — Owner, Admin, Member. This covers the vast majority of SaaS use cases. Custom roles and granular permissions are a post-launch concern for products that have proven the need for them.

01

Owner

The account creator and primary account holder. Has all permissions across the organisation. Can transfer ownership, delete the organisation, and manage billing.

Can Do

  • All admin permissions
  • Transfer organisation ownership
  • Delete the organisation and all data
  • Manage subscription and billing
  • Create and delete API keys
  • Invite and remove admins
02

Admin

Trusted team members with elevated privileges. Can manage the workspace, invite members, and perform all product operations. Cannot touch billing or delete the organisation.

Can Do

  • All member permissions
  • Invite and remove members
  • Create and manage workspaces
  • View all member activity
  • Configure integrations
  • Export organisation data

Cannot Do

  • Manage billing
  • Delete the organisation
  • Transfer ownership
  • Manage API keys
03

Member

Standard workspace users. Can use all product features but cannot manage the organisation, invite others, or access admin settings. The default role for invited team members.

Can Do

  • Access all product core features
  • Create and edit their own content
  • View shared organisation content
  • Update their own profile
  • Use integrations configured by admin

Cannot Do

  • Invite new members
  • Remove other members
  • Access admin settings
  • View billing
  • Export data
📐

RBAC Enforcement Layers

Role checks must be enforced at three independent layers: (1) Database RLS — policies block unauthorised writes regardless of application bugs. (2) API middleware — every protected route checks role before executing. (3) UI layer — components conditionally render based on role for UX only (never for security). All three must exist. Removing any one creates a bypass vector.

▸ Auth Flows

Three critical auth flows — step by step

These are the three flows that every SaaS product must implement correctly. Each step has a defined outcome — missing any step creates a security gap or a broken user experience.

01

New User Signup

6 steps
01

User submits email + password (or clicks OAuth)

Client-side validation. Password strength check. Duplicate email check via Supabase.

02

Supabase Auth creates user record

Hashed password stored. Confirmation email sent with verification token. Unconfirmed user created.

03

User verifies email

Click link in email. Token validated. User marked as confirmed. Session JWT issued.

04

Onboarding flow triggered

Check if user has an organisation. If not, prompt to create one or accept pending invitation.

05

Organisation and membership created

Create organisation record. Create membership record with role 'owner'. Provision free plan subscription.

06

User lands in dashboard

Auth context loaded. Organisation context loaded. Feature flags applied based on plan.

02

Team Member Invitation

5 steps
01

Admin sends invitation

Invitation record created with token, role, email, and 48-hour expiry. Email sent via Resend.

02

Invitee clicks invitation link

Token validated against invitations table. Expiry checked. Already-accepted check.

03

Account creation or login

If new user — show signup form with email pre-filled. If existing user — show login prompt. OAuth allowed.

04

Membership created

Membership record created with organisation_id and role from invitation. Invitation marked as accepted_at = now().

05

User enters organisation workspace

Auth context includes new organisation. Organisation switcher available if user belongs to multiple orgs.

03

Protected Route Access

6 steps
01

Request hits Next.js middleware

JWT extracted from cookie. Supabase client verifies signature. Expired tokens trigger automatic refresh.

02

User identity confirmed

auth.uid() extracted from verified JWT. No database lookup required — stateless validation.

03

Organisation context loaded

Membership record fetched: SELECT * FROM memberships WHERE user_id = auth.uid(). Role extracted.

04

Route-level authorisation check

Required role compared against user's role for this organisation. Admin-only routes reject member-role requests.

05

Plan-level feature gate

Subscription status checked. Feature flag evaluated against plan tier. Upgrade prompt shown if gated.

06

Request proceeds to handler

All database queries automatically scoped by RLS policies — no manual organisation_id filtering in handlers.

▸ Middleware Patterns

Six auth middleware patterns every SaaS API needs

These six middleware layers are stacked in sequence for every protected route. Each one handles a specific access concern — skipping any one creates a gap.

middleware/01.ts

Public Route Guard

Marketing pages and auth pages are public. Authenticated users visiting /login are redirected to their dashboard — they're already in.

// Allow: /, /login, /signup, /pricing, /blog/* // Redirect to /dashboard if already authenticated
middleware/02.ts

Protected Route Guard

All dashboard routes require a valid, non-expired JWT and email verification. Unauthenticated requests redirect to login with the intended path preserved.

// Require: valid JWT + confirmed email // Redirect to /login?next={currentPath} if unauthenticated
middleware/03.ts

Role Guard

Admin-only routes (settings, billing, member management) check the user's role in the current organisation before allowing access.

// Require: role IN ('owner', 'admin') for /settings/* // Return 403 Forbidden if role is 'member'
middleware/04.ts

Plan Guard

Feature-gated routes check subscription status and plan tier. Free and trial users see upgrade prompts instead of the gated feature.

// Require: subscription.status = 'active' for paid features // Show upgrade prompt if status = 'trialing' or 'free'
middleware/05.ts

Org Context Guard

Multi-organisation setups verify that the user is actually a member of the organisation referenced in the URL — not just authenticated globally.

// Require: valid orgSlug in URL params // Verify user is a member of that specific organisation
middleware/06.ts

API Rate Limit Guard

API routes enforce per-token rate limits. Auth endpoints enforce per-IP rate limits using Upstash Redis to prevent brute force and abuse.

// Limit: 100 req/min per user token for /api/* // Limit: 10 req/15min per IP for /auth/*

▸ Multi-Factor Authentication

MFA for SaaS — three methods and when to use each

MFA reduces account takeover risk by 99.9%. Here are the three methods available for SaaS products — with implementation detail and guidance on which to prioritise.

📱

TOTP (Time-Based One-Time Password)

Users scan a QR code with an authenticator app (Google Authenticator, Authy, 1Password). The app generates a 6-digit code that rotates every 30 seconds.

How It Works

Server generates a shared secret. User scans QR. App derives codes from secret + timestamp. Server validates submitted code against current and previous time window.

Best For

All SaaS products — the standard MFA method. Supabase Auth supports TOTP out of the box.

📧

Email OTP

A 6-digit one-time code sent to the user's registered email address as a second factor. Less secure than TOTP (depends on email account security) but lower friction for non-technical users.

How It Works

Server generates a short-lived code (5-minute expiry). User receives email with code. User submits code alongside password. Server validates against stored hash.

Best For

Consumer-facing SaaS where users are unlikely to use authenticator apps. Good fallback when TOTP device is unavailable.

🔑

WebAuthn / Passkeys

Biometric or hardware key-based authentication using the WebAuthn standard. Users authenticate with Face ID, Touch ID, or a physical security key (YubiKey). Phishing-resistant by design.

How It Works

Browser generates public/private key pair. Public key stored server-side. Private key stays on device. Each login signed by device — cryptographically bound to the domain.

Best For

Security-conscious B2B SaaS and enterprise products where phishing resistance is a requirement. Growing adoption as passkeys become mainstream.

Free / TrialMFA Optional

Make MFA available in account settings but do not require it. Encourage it with a setup prompt but never block access.

Pro / GrowthMFA Recommended

Prompt admin and owner roles to enable MFA. Show a security score or warning in settings. Do not block access but make it visible.

EnterpriseMFA Required

Enforce MFA for all users in the organisation. Block access until MFA is configured. Org-level setting controllable by owner.

▸ Security Hardening

Six security controls every SaaS auth system must implement

These six controls address the most common auth vulnerabilities in SaaS products. Each one eliminates a specific attack vector — and all six are implemented by default in every 4Byte build.

Token Security

httpOnly Cookies for Token Storage

PreventsXSS token theft

What It Does

JWT access tokens and refresh tokens are stored in httpOnly cookies — not localStorage or sessionStorage. httpOnly cookies are inaccessible to JavaScript, eliminating XSS-based token theft.

Implementation

Set-Cookie: sb-access-token=...; HttpOnly; Secure; SameSite=Lax; Path=/
Session Security

Short JWT Expiry with Refresh Tokens

PreventsLong-lived token compromise

What It Does

Access tokens expire after 15–60 minutes. Refresh tokens issue new access tokens automatically and silently. This limits the window of exposure if a token is somehow compromised.

Implementation

Supabase default: 1-hour access token, 7-day refresh token with rotation on each use.
Identity Verification

Email Verification Before Access

PreventsFake account abuse

What It Does

New accounts cannot access the product until their email address is verified. Prevents fake account creation, reduces spam, and ensures a valid contact point for all users.

Implementation

Supabase Auth sends verification email on signup. Route middleware checks email_confirmed_at IS NOT NULL.
Brute Force Prevention

Rate Limiting on Auth Endpoints

PreventsBrute force & stuffing

What It Does

Login, signup, magic link, and password reset endpoints are rate-limited by IP address. Prevents brute force attacks, credential stuffing, and email bombing of the reset endpoint.

Implementation

10 attempts per IP per 15 minutes on login. 3 magic link sends per email per hour. Upstash Redis for distributed rate limiting.
Session Integrity

Session Rotation on Privilege Change

PreventsStale privilege sessions

What It Does

When a user's role changes, their password is reset, or they upgrade to a higher-privilege plan, the current session is invalidated and a new one is issued. Prevents privilege escalation from stale sessions.

Implementation

Call supabase.auth.signOut() then re-authenticate, or use admin API to invalidate sessions for a specific user.
OAuth Security

PKCE Flow for OAuth

PreventsOAuth code interception

What It Does

OAuth flows use PKCE (Proof Key for Code Exchange) instead of the implicit flow. PKCE prevents authorization code interception attacks by binding the code exchange to the original request.

Implementation

Supabase Auth uses PKCE by default for all OAuth flows. No additional configuration required.

▸ Auth Mistakes

Auth mistakes that create serious security vulnerabilities

These six mistakes appear regularly in SaaS products that were built quickly without security-first thinking. Every one is preventable and expensive to fix after launch.

Storing JWT tokens in localStorage

Security Risk

localStorage is accessible to any JavaScript on the page — including injected scripts from XSS attacks. A single XSS vulnerability exposes every active user's session token.

4Byte Security Standard

Always store JWTs in httpOnly, Secure, SameSite=Lax cookies. These are inaccessible to JavaScript by design. Supabase Auth handles this correctly by default when using SSR.

Not verifying email before granting product access

Security Risk

Unverified emails allow anyone to create accounts using someone else's email address. The real owner is locked out, and the account may be used for spam or abuse.

4Byte Security Standard

Block product access until email_confirmed_at is set. Redirect unverified users to a 'check your email' page. Provide a resend verification option with rate limiting.

Enforcing permissions only in the UI layer

Security Risk

UI-only guards (hiding buttons, disabling links) are trivially bypassed by making direct API calls. A member-role user can perform admin operations by crafting HTTP requests.

4Byte Security Standard

Enforce all role checks at the API layer via middleware, independent of what the UI shows. The database RLS layer adds a third enforcement point. UI guards are UX only — never security.

Implementing custom password hashing

Security Risk

Rolling custom password storage (MD5, SHA-256, or custom bcrypt) introduces implementation errors that cause mass credential exposure. This is the leading cause of high-profile breaches.

4Byte Security Standard

Never implement custom password storage. Use Supabase Auth, NextAuth.js, or another battle-tested auth library. These implement bcrypt with appropriate cost factors and salt generation.

No rate limiting on password reset endpoint

Security Risk

Unprotected password reset endpoints can be exploited to send hundreds of reset emails to any address — causing email spam abuse and potential account enumeration.

4Byte Security Standard

Rate limit password reset to 3 requests per email address per hour. Rate limit by IP as well. Return a generic success message regardless of whether the email exists — never confirm account existence.

Not invalidating sessions on password change

Security Risk

If a user's password is changed (by them or via admin reset), old sessions remain valid. An attacker who had gained session access retains it even after the password change.

4Byte Security Standard

On password change or admin-initiated reset, invalidate all existing sessions for that user via Supabase Admin API and force re-authentication. Issue a new session only after the new credentials are confirmed.

▸ FAQ

Frequently asked questions about SaaS authentication

What is the best authentication method for a SaaS product?+

For most SaaS products in 2025, the best authentication approach combines email/password login with OAuth providers (Google, GitHub) and magic link options. Managed auth via Supabase Auth handles JWT token management, session refresh, and multi-provider support out of the box — eliminating weeks of custom auth infrastructure build.

Should a SaaS use JWT or session-based authentication?+

Most SaaS products use JWT (JSON Web Tokens) because they are stateless, work well with serverless and Edge deployments, and integrate natively with row-level security in PostgreSQL. Session-based auth is a valid alternative for monolithic deployments where immediate token revocation is a hard requirement. Supabase Auth uses JWTs with automatic refresh — the recommended approach for Next.js SaaS products.

What is role-based access control (RBAC) in a SaaS product?+

RBAC (Role-Based Access Control) is a permission model where users are assigned roles (owner, admin, member) and each role has a defined set of allowed actions. In a SaaS product, RBAC is implemented at three levels: the database layer (RLS policies check role), the API layer (middleware verifies role before executing operations), and the UI layer (components render based on role).

How do you implement OAuth in a SaaS product?+

OAuth in a SaaS product is implemented via an auth provider (Supabase Auth, NextAuth.js, or Clerk) that handles the OAuth flow with Google, GitHub, LinkedIn, or other providers. The provider handles the redirect, token exchange, and user creation. Your application receives a user record with a verified email — you then create or link the user to their organisation and membership record.

Should a SaaS product require multi-factor authentication (MFA)?+

MFA should be optional (user-configurable) in most SaaS products at MVP stage and mandatory for admin and owner roles in enterprise-tier plans. Supabase Auth supports TOTP-based MFA (Google Authenticator, Authy) out of the box. Enforce MFA at the API middleware level for sensitive operations regardless of whether the UI has enforced it.

How does 4Byte Agency implement authentication in SaaS products?+

4Byte Agency uses Supabase Auth as the primary authentication layer for all SaaS products. This provides email/password, OAuth (Google, GitHub), magic links, and TOTP MFA out of the box. JWTs are used for session management with automatic refresh. RBAC is implemented at both the database level (RLS policies) and API middleware level. Auth is set up in the first week of every build.

▸ Ship auth correctly from day one

Need your SaaS auth system built securely and fast?

We implement the full auth stack — email/password, OAuth, magic links, RBAC, MFA, and all six security controls — in the first week of every build. Using the exact patterns from this guide, refined across 45+ products.

Available now
Security review included free
Response in ≤ 4 hours
45+ products shipped