ShipNext

Authentication

Configure Better Auth, email/password, magic links, Google, GitHub, and server-side auth helpers.

ShipNext uses Better Auth as the authentication framework. It supports email/password login, magic links, social login, session management, and server-side helpers.

Environment variables

Set these values in .env.local:

VariableDescription
BETTER_AUTH_URLBetter Auth root URL. Keep it equal to NEXT_PUBLIC_APP_URL.
BETTER_AUTH_SECRETSigning secret for sessions and tokens.
BETTER_AUTH_URL=http://localhost:3000
# Generate with: openssl rand -base64 32
BETTER_AUTH_SECRET=your-secret-key

Google login

Create OAuth credentials

Open Google Cloud Console, choose or create a project, then click Create credentials and select OAuth client ID.

Configure the web application

Choose Web application.

  • Name: Any name.
  • Authorized JavaScript origins: Your domain, for example https://your-domain.com or http://localhost:3000.
  • Authorized redirect URIs: http://localhost:3000/api/auth/callback/google locally, or https://your-domain.com/api/auth/callback/google in production.

The /api/auth/callback/google path is fixed by Better Auth.

Add the environment variables

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

Enable Google in website config

const authConfig = {
  enableEmailVerification: true,
  enableCredentialLogin: true,
  enableMagicLinkLogin: true,
  enableGoogleLogin: true, 
  enableGitHubLogin: true,
  captcha: {
    enable: false,
    scenarios: {
      signIn: false,
      signUp: false,
    },
  },
};

GitHub login

Create an OAuth App

Open GitHub Developer Settings, then click New OAuth app.

Fill in callback settings

  • Application name: Any name.
  • Homepage URL: http://localhost:3000 locally or your production domain.
  • Authorization callback URL: http://localhost:3000/api/auth/callback/github locally, or https://your-domain.com/api/auth/callback/github in production.

The /api/auth/callback/github path is fixed by Better Auth.

Generate a client secret

After registering the app, click Generate a new client secret.

Add environment variables

GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

Enable GitHub in website config

const authConfig = {
  enableEmailVerification: true,
  enableCredentialLogin: true,
  enableMagicLinkLogin: true,
  enableGoogleLogin: true,
  enableGitHubLogin: true, 
  captcha: {
    enable: false,
    scenarios: {
      signIn: false,
      signUp: false,
    },
  },
};

Email login

Email registration and sign-in require an email provider. ShipNext defaults to Resend; see Email.

ShipNext enables email/password login and email verification by default:

const authConfig = {
  enableEmailVerification: true, 
  enableCredentialLogin: true, 
  enableMagicLinkLogin: true,
  enableGoogleLogin: true,
  enableGitHubLogin: true,
  captcha: {
    enable: false,
    scenarios: {
      signIn: false,
      signUp: false,
    },
  },
};

Email verification is strongly recommended in production to reduce abuse and account takeover risk.

Magic links are passwordless login links sent by email. They are enabled by enableMagicLinkLogin.

const authConfig = {
  enableMagicLinkLogin: true, 
  // ...
};

Magic links apply to login. Registration still uses email activation when verification is enabled.

Client usage

Common client-side operations are exposed from src/modules/auth/client.ts.

Read session state

import { useAuth } from "@/modules/auth/client";

const { session } = useAuth();
if (session.loading) {
  return <div>Loading...</div>;
}

Email sign-in

import { useAuth } from "@/modules/auth/client";

const { signIn } = useAuth();
await signIn.email({ email, password });

Sign out

import { useAuth } from "@/modules/auth/client";

const { signOut } = useAuth();
await signOut();
import { useAuth } from "@/modules/auth/client";

const { signIn } = useAuth();
await signIn.magicLink({ email });

Social login

import { useAuth } from "@/modules/auth/client";

const { signIn } = useAuth();
await signIn.social({ provider: "google" });

Server usage

Server helpers live in src/modules/auth/server.ts.

Protect an API route

import { getUser } from "@/modules/auth/server";
import { unauthorizedResponse } from "@/core/response/responses";

export async function GET(request: NextRequest) {
  const user = await getUser(request);
  if (!user) {
    return unauthorizedResponse();
  }

  return NextResponse.json({ user });
}

Require admin

import { requireAdmin } from "@/modules/auth/server";

export async function POST(request: NextRequest) {
  const user = await requireAdmin(request);
  // other code
}

On this page