How Dify Chat Handles User Authentication: Next-Auth 4 and Prisma Implementation

Dify Chat uses Next-Auth 4 with a custom CredentialsProvider to validate email and password credentials against a Prisma database, storing sessions as JWTs and securing routes with getServerSession.

Dify Chat, the open-source conversational platform maintained by lexmin0412, implements a secure authentication layer built on Next-Auth 4 and Prisma. This article examines the specific implementation details in the dify-chat repository, covering how the platform handles credential validation, session management, and API route protection.

Next-Auth Configuration and Prisma Adapter

The authentication logic is centralized in packages/platform/lib/auth.ts, where the authOptions object configures Next-Auth to use a PrismaAdapter for persistent storage.

The adapter connects to the same Prisma client used throughout the application:

// packages/platform/lib/auth.ts
export const authOptions = {
  adapter: PrismaAdapter(getPrisma() as any),
  providers: [
    // CredentialsProvider defined here...
  ],
  session: { strategy: 'jwt' },
  pages: { signIn: '/login' },
  callbacks: {
    async jwt({ token, user }) { 
      if (user) token.id = user.id; 
      return token; 
    },
    session({ session, token }) { 
      if (token && session.user) session.user.id = token.id as string; 
      return session; 
    },
  },
};

This configuration ensures that user accounts and sessions are stored in the database managed by Prisma, while the JWT strategy enables stateless session validation.

Credentials Provider and bcryptjs Verification

Authentication relies on a CredentialsProvider that accepts email and password fields. In the authorize callback at packages/platform/lib/auth.ts, the system performs two critical operations at specific line ranges:

  • User Lookup (lines 24-27): Queries the database using prisma.user.findUnique to locate the user record by email.
  • Password Verification (lines 33-36): Uses bcryptjs to compare the supplied password against the stored hash via bcrypt.compare.

If verification succeeds, the callback returns a minimal user object (lines 39-43) containing id, email, and name:

// Simplified from packages/platform/lib/auth.ts
async authorize(credentials) {
  const user = await prisma.user.findUnique({
    where: { email: credentials.email }  // Lines 24-27
  });
  
  if (!user) return null;
  
  const isValid = await bcrypt.compare(credentials.password, user.password);  // Lines 33-36
  if (!isValid) return null;
  
  return { id: user.id, email: user.email, name: user.name };  // Lines 39-43
}

API Route Protection

Protected endpoints verify authentication using getServerSession. For example, in packages/platform/app/api/users/route.ts, the handler first validates the session before executing business logic:

// packages/platform/app/api/users/route.ts
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/lib/auth';

export async function GET() {
  const session = await getServerSession(authOptions);
  if (!session) {
    return NextResponse.json({ message: '未授权' }, { status: 401 });
  }
  // Authorized logic proceeds here...
}

This pattern returns a 401 Unauthorized response when no valid session exists, ensuring that sensitive data remains inaccessible to unauthenticated clients.

Authentication Route Handler

The Next-Auth API endpoint is defined at packages/platform/app/api/auth/[...nextauth]/route.ts using Next.js 13's App Router syntax. This file exports GET and POST handlers that process all authentication requests:

// packages/platform/app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth/next';
import { authOptions } from '@/lib/auth';

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

This setup automatically handles /api/auth/signin, /api/auth/signout, and callback URLs without requiring additional route definitions.

Client-Side Authentication

For browser-based authentication, Dify Chat uses the signIn function from next-auth/react. This enables credential submission without page reloads:

// Client-side login implementation
import { signIn } from 'next-auth/react';

async function handleLogin(email: string, password: string) {
  const result = await signIn('credentials', {
    redirect: false,
    email,
    password,
  });
  
  if (result?.error) {
    console.error('Authentication failed:', result.error);
  } else {
    // Session cookie automatically set
    window.location.href = '/dashboard';
  }
}

Setting redirect: false allows the application to handle authentication errors programmatically while still receiving the session cookie upon success.

Summary

  • Next-Auth 4 provides the authentication framework with JWT-based session strategy configured in packages/platform/lib/auth.ts
  • PrismaAdapter persists user data and sessions in the PostgreSQL database via Prisma ORM
  • bcryptjs handles secure password comparison during the credential validation phase at lines 33-36 of the auth configuration
  • getServerSession protects API routes by validating JWTs on the server side before executing sensitive operations
  • The App Router implementation at packages/platform/app/api/auth/[...nextauth]/route.ts exposes standard OAuth endpoints for sign-in and sign-out flows

Frequently Asked Questions

How does Dify Chat store user passwords securely?

Dify Chat stores passwords as hashed strings using bcryptjs. During authentication in packages/platform/lib/auth.ts, the system retrieves the stored hash from the Prisma database and uses bcrypt.compare() (lines 33-36) to verify the supplied password against the hash without ever decrypting the original value.

What session strategy does Dify Chat use?

The platform uses JWT (JSON Web Token) sessions configured with session: { strategy: 'jwt' } in the auth options. This stateless approach stores the user ID in an encrypted token on the client side, eliminating the need for database session lookups on every request while maintaining security through the JWT signature.

How can I protect a new API route in Dify Chat?

Import getServerSession from next-auth/next and call it with the authOptions imported from @/lib/auth. Check if the returned session object is null—if so, return a 401 response. Otherwise, proceed with the authenticated logic using the session.user.id property to identify the requesting user.

Where is the authentication configuration defined?

All Next-Auth configuration resides in packages/platform/lib/auth.ts, including the PrismaAdapter setup, CredentialsProvider definition, bcryptjs password verification logic, and JWT callbacks. The API route handler that exposes these endpoints is located at packages/platform/app/api/auth/[...nextauth]/route.ts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →