Building Secure Authentication and Authorization in Next.js

January 15, 2025

Learn how to implement secure authentication in Next.js using AuthJS, with best practices for SaaS security.

Building Secure Authentication and Authorization in Next.js

Free Guide: Build a Successful SaaS

Learn the key steps from The Lean Startup and Zero to One to create a winning SaaS business.

Authentication and authorization are the backbone of any SaaS business. If you mess them up, bad actors can take over accounts, steal data, or exploit your service.

Let’s go step by step on how to build a solid auth system in Next.js with AuthJS (formerly NextAuth.js). This guide keeps things practical and straightforward.

Common Auth Methods

There are different ways to handle authentication:

JWTs (JSON Web Tokens) are popular for APIs. They let the frontend send a signed token with each request. Downside? If a token gets leaked, an attacker can impersonate a user until it expires.

Sessions store user data on the server. The client gets a session ID, which they send with each request. More secure than JWTs because tokens aren’t flying around everywhere.

OAuth (Google, GitHub, Twitter logins) lets users sign in with existing accounts. Less friction for users, but third-party auth means you're depending on another service.

Which one should you use? For most SaaS apps, session-based auth with OAuth options is the best mix of security and ease of use.

Why Security Matters in Subscription Models

If you’re running a SaaS, security isn’t just about avoiding hacks. It's about keeping users’ trust.

Imagine if someone hijacks accounts and changes billing details. Now your paying customers are getting unexpected charges. Refund requests pile up. Support is overwhelmed. People cancel.

Or worse—if you store passwords insecurely and there’s a breach, your users might reuse that password elsewhere. They’ll blame you for any damage.

Strong authentication protects your revenue and reputation.

Setting Up Secure Auth in Next.js with AuthJS

Let’s implement authentication using AuthJS.

Install Dependencies

If you haven’t already, install the required packages:

npm install next-auth @auth/core

Create an Auth API Route

Next.js has a built-in API layer. Let’s create an authentication handler.

In pages/api/auth/[...nextauth].js:

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import GitHubProvider from "next-auth/providers/github";

export default NextAuth({
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
    }),
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        const user = await authenticateUser(
          credentials.email,
          credentials.password
        );
        if (user) return user;
        throw new Error("Invalid credentials");
      },
    }),
  ],
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async session({ session, token }) {
      session.user.id = token.sub;
      return session;
    },
  },
  secret: process.env.NEXTAUTH_SECRET,
});

Protecting API Routes

If you have private API routes, protect them.

Example: pages/api/protected.js:

import { getServerSession } from "next-auth";
import authOptions from "./auth/[...nextauth]";

export default async function handler(req, res) {
  const session = await getServerSession(req, res, authOptions);

  if (!session) {
    return res.status(401).json({ message: "Unauthorized" });
  }

  res.json({ message: "This is a protected route" });
}

Storing Session Tokens Securely

AuthJS lets you store sessions in a database. For production, don’t use the default JWT session strategy. Instead, set up a database adapter.

npm install @auth/prisma-adapter

Then update authOptions:

import { PrismaAdapter } from "@auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default NextAuth({
  adapter: PrismaAdapter(prisma),
  ...
});

This way, session data is stored in the database instead of being sent as JWTs.

Best Practices for Password Management

Don’t store passwords as plain text. Always hash them. Use bcrypt:

npm install bcrypt

Hash passwords before saving:

import bcrypt from "bcrypt";

async function hashPassword(password) {
  return await bcrypt.hash(password, 10);
}

When verifying:

async function verifyPassword(inputPassword, storedHash) {
  return await bcrypt.compare(inputPassword, storedHash);
}

Use strong password policies. Enforce minimum length and complexity.

Email Verification

When a user signs up, send a verification email before activating their account. Use a service like Resend, SendGrid, or Postmark.

import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

async function sendVerificationEmail(email, token) {
  await resend.send({
    from: "no-reply@yourapp.com",
    to: email,
    subject: "Verify your email",
    text: `Click this link to verify: https://yourapp.com/verify?token=${token}`,
  });
}

Require users to verify before they can log in.

Wrapping Up

Security isn’t just about avoiding hacks—it’s about protecting your business.

Use session-based auth for most SaaS apps. Store sessions in a database, not just JWTs. Hash passwords and enforce strong policies. Verify user emails before allowing access.

A secure authentication system helps you build trust and keep your SaaS revenue safe.

The Next.js Starter Kit for Subscription-Based SaaS

Build and monetize your SaaS without worrying about infrastructure—auth, payments, marketing, and headless APIs are ready to go.

Related Articles

Set Up Payments for Your SaaS

Easily set up payments for your SaaS business. Learn how to choose the right tools to get started quickly.

Set Up Payments for Your SaaS cover
SaaS
payments
setup
tools

SaaS Pricing Models Explained: Tiered, Freemium, and More

Learn about different SaaS pricing models like tiered, freemium, and usage-based pricing. Discover the pros and cons of each model and how to implement flexible pricing with FastStartup.dev.

SaaS Pricing Models Explained: Tiered, Freemium, and More cover
SaaS
pricing
subscriptions