Authentication

Secure user authentication with Auth.js v5, Google OAuth, and Supabase user sync.

shipsaas uses Auth.js v5 (NextAuth) with Google OAuth pre-configured. Users are automatically synced to your Supabase database on first sign-in.

Configuration

Environment Variables

Add the following to your .env.local file:

.env.local
# Generate a secret: openssl rand -base64 32
AUTH_SECRET=your-auth-secret-here

# Google OAuth (https://console.developers.google.com/)
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret

Generate a secure secret: Run openssl rand -base64 32 in your terminal to generate a random secret key.

Auth.js Configuration

Authentication is configured in lib/auth.js. It exports auth, signIn, signOut, and handlers.

lib/auth.js

Auth.js v5 configuration with Google OAuth, Supabase user sync, and session callbacks.

View Source
lib/auth.js
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import supabase from "./supabase";

// User helpers — auto-create users in Supabase on first sign-in
async function getUser(email) {
  const { data } = await supabase
    .from("users")
    .select("*")
    .eq("email", email)
    .single();
  return data;
}

async function createUser(newUser) {
  const { data, error } = await supabase.from("users").insert([newUser]);
  if (error) throw new Error("User could not be created");
  return data;
}

const authConfig = {
  providers: [
    Google({
      clientId: process.env.AUTH_GOOGLE_ID,
      clientSecret: process.env.AUTH_GOOGLE_SECRET,
    }),
    // TODO: Add more providers (GitHub, Discord, etc.)
  ],
  callbacks: {
    authorized({ auth }) {
      return !!auth?.user;
    },
    async signIn({ user }) {
      const existingUser = await getUser(user.email);
      if (!existingUser) {
        await createUser({ email: user.email, full_name: user.name });
      }
      return true;
    },
    async session({ session }) {
      const dbUser = await getUser(session.user.email);
      if (dbUser) session.user.id = dbUser.id;
      return session;
    },
  },
  pages: { signIn: "/login" },
};

export const { auth, signIn, signOut, handlers } = NextAuth(authConfig);

Route Handler

The Auth.js route handler lives at app/api/auth/[...nextauth]/route.ts:

app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/lib/auth";
export const { GET, POST } = handlers;

Usage

Server-Side Authentication

Protect server components by importing auth from lib/auth:

import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";

export default async function ProtectedPage() {
  const session = await auth();

  if (!session?.user) {
    redirect("/login");
  }

  return (
    <div>
      <h1>Welcome, {session.user.name}</h1>
      <p>Email: {session.user.email}</p>
    </div>
  );
}

Client-Side Sign In / Sign Out

Use the signIn and signOut functions from next-auth/react:

"use client";

import { signIn, signOut } from "next-auth/react";

// Sign in with Google
<button onClick={() => signIn("google")}>
  Sign in with Google
</button>

// Sign out
<button onClick={() => signOut()}>
  Sign Out
</button>

OAuth Providers

To set up Google OAuth:

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable Google+ API
  4. Create OAuth 2.0 credentials
  5. Add authorized redirect URI: http://localhost:3000/api/auth/callback/google
  6. Copy Client ID and Secret to AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET in .env.local

Adding More Providers

Add providers in lib/auth.js:

import GitHub from "next-auth/providers/github";
import Discord from "next-auth/providers/discord";

providers: [
  Google({ ... }),
  GitHub({
    clientId: process.env.AUTH_GITHUB_ID,
    clientSecret: process.env.AUTH_GITHUB_SECRET,
  }),
  Discord({
    clientId: process.env.AUTH_DISCORD_ID,
    clientSecret: process.env.AUTH_DISCORD_SECRET,
  }),
]

✓ You're all set! Authentication is configured with automatic Supabase user sync. Next, configure database integration to customize your user schema.