Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dev0302/nextjs-project-1/llms.txt

Use this file to discover all available pages before exploring further.

AnonMessage does not expose a hand-written sign-in route. Authentication is handled entirely by NextAuth.js using the built-in CredentialsProvider. When a user submits their credentials, NextAuth processes the request at POST /api/auth/callback/credentials, validates the credentials against MongoDB, and issues a signed JWT session cookie that carries custom user fields.

How Sign-In Works

NextAuth intercepts requests to /api/auth/callback/credentials — you do not call this URL directly from application code. Instead, you use the signIn() helper from next-auth/react (client components) or inspect the session with getServerSession() (server components and API routes). Under the hood, NextAuth’s authorize callback:
  1. Connects to MongoDB via dbConnect().
  2. Looks up the user document by email (User.findOne({ email })).
  3. Calls bcrypt.compare(password, user.password) to validate the supplied password against the stored hash.
  4. Returns the user object on success, or throws a descriptive error ("User not found", "Invalid password") on failure.

Credentials

FieldTypeDescription
emailstringThe registered email address of the account.
passwordstringThe plain-text password. Compared against the bcrypt hash stored in MongoDB.

JWT and Session Enrichment

After a successful authorize call, NextAuth runs the jwt and session callbacks to attach custom fields that are not part of the NextAuth default type definitions. The following fields are added to every JWT and forwarded into the session object:
FieldSource
_iduser.id?.toString() — the MongoDB ObjectId as a string
isVerifiedWhether the user completed OTP verification at sign-up
isAcceptingMessagesWhether the user’s inbox is currently open to anonymous messages
usernameThe user’s chosen display name

Session Object Shape

The full session object available in both server and client contexts conforms to the following TypeScript interface, extended via next-auth.d.ts:
interface Session {
  user: {
    _id?: string;
    isVerified?: boolean;
    isAcceptingMessages?: boolean;
    username?: string;
    // Standard NextAuth fields
    name?: string;
    email?: string;
    image?: string;
  }
}

Calling Sign-In from a Client Component

Use the signIn function from next-auth/react. Pass 'credentials' as the provider ID along with the user’s email and password. Supply a callbackUrl to control where NextAuth redirects on success.
'use client';

import { signIn } from 'next-auth/react';

async function handleSignIn(email: string, password: string) {
  const result = await signIn('credentials', {
    email,
    password,
    callbackUrl: '/dashboard',
    redirect: false, // set true to let NextAuth handle the redirect automatically
  });

  if (result?.error) {
    // NextAuth surfaces the error thrown inside `authorize` here
    console.error('Sign-in failed:', result.error);
  }
}

Reading the Session in Server Components

Use getServerSession with the exported NEXT_AUTH_CONFIG options object to access the enriched session on the server side without an additional network request.
import { getServerSession } from 'next-auth';
import { NEXT_AUTH_CONFIG } from '@/app/lib/auth';

export default async function DashboardPage() {
  const session = await getServerSession(NEXT_AUTH_CONFIG);

  if (!session || !session.user) {
    // Handle unauthenticated state
    return <p>Please sign in.</p>;
  }

  const { username, isVerified, isAcceptingMessages, _id } = session.user;

  return (
    <div>
      <p>Welcome, {username}!</p>
      <p>Verified: {isVerified ? 'Yes' : 'No'}</p>
    </div>
  );
}

Reading the Session in Client Components

Use the useSession hook from next-auth/react. Wrap the component tree with NextAuth’s SessionProvider at the layout level for this hook to work.
'use client';

import { useSession } from 'next-auth/react';

export default function ProfileBadge() {
  const { data: session, status } = useSession();

  if (status === 'loading') return <p>Loading...</p>;
  if (status === 'unauthenticated') return <p>Not signed in.</p>;

  const { username, isVerified, isAcceptingMessages } = session!.user;

  return (
    <div>
      <p>{username}</p>
      <p>{isVerified ? '✓ Verified' : 'Unverified'}</p>
    </div>
  );
}

Error Handling

When authorize throws an error, NextAuth appends an error query parameter to the redirect URL. For CredentialsProvider, the value is always CredentialsSignin regardless of the underlying message (e.g., “User not found” vs. “Invalid password”).
/signin?error=CredentialsSignin
Read this parameter on your custom sign-in page to display a generic “Invalid email or password” message to the user. Avoid exposing the specific reason for failure to prevent user-enumeration attacks.

Sign Out

Call signOut from next-auth/react to clear the JWT session cookie and redirect the user.
'use client';

import { signOut } from 'next-auth/react';

function SignOutButton() {
  return (
    <button onClick={() => signOut({ callbackUrl: '/' })}>
      Sign out
    </button>
  );
}
The NEXTAUTH_SECRET environment variable must be set in your .env.local file (and in your production environment). NextAuth uses this value to sign and verify the JWT session cookie. Without it, the application will fail to start or will be unable to verify session tokens.
# .env.local
NEXTAUTH_SECRET=your-strong-random-secret
The session strategy is "jwt", meaning no session records are written to the database. Revoking a session requires rotating NEXTAUTH_SECRET, which will invalidate all active sessions across all users.

Build docs developers (and LLMs) love