NextAuth.js Authentication Series — Part 5 ~ Integrating MongoDB with Auth.js Credentials Authentication
In the previous article, we implemented email and password authentication using the Credentials Provider with a hardcoded user. While this helped us understand...

In the previous article, we implemented email and password authentication using the Credentials Provider with a hardcoded user. While this helped us understand how the authentication flow works, it's not suitable for real-world applications.
In this article, we'll connect our application to MongoDB, allowing us to store and retrieve user information from a database instead of relying on hardcoded data.
By the end of this guide, our authentication system will be ready to work with real users.
Why Do We Need a Database?
Using a hardcoded user has several limitations:
Users cannot register.
Data is lost whenever the application restarts.
Passwords cannot be updated.
User profiles cannot be managed.
A database solves these problems by storing user information permanently.
For this series, we'll use MongoDB because it's flexible, easy to integrate with Next.js, and a popular choice for modern applications.
Installing MongoDB Driver
Install the official MongoDB driver.
npm install mongodb
Unlike relational databases, MongoDB doesn't require an ORM for basic operations. The official driver is lightweight and works perfectly with Auth.js.
Setting Up Environment Variables
Open your .env.local file and add your MongoDB connection string.
MONGODB_URI=mongodb://localhost:27017/next-auth-demo
NEXTAUTH_SECRET=your-secret
NEXTAUTH_URL=http://localhost:3000
If you're using MongoDB Atlas, your connection string will look similar to:
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/next-auth-demo
Never expose your database credentials publicly.
Creating a MongoDB Connection
Create a new file:
lib/mongodb.ts
import { MongoClient } from "mongodb";
const uri = process.env.MONGODB_URI!;
const client = new MongoClient(uri);
export async function connectDB() {
if (!client.topology?.isConnected()) {
await client.connect();
}
return client.db();
}
This helper ensures we reuse the same MongoDB client instead of creating a new connection for every request.
Creating the Users Collection
MongoDB creates collections automatically when data is inserted.
A typical user document might look like this:
{
"_id": "...",
"name": "John Doe",
"email": "john@example.com",
"password": "hashed-password",
"createdAt": "2026-01-01T10:00:00.000Z"
}
Notice that we're storing a hashed password, not the plain text password.
We'll implement password hashing in the next article.
Updating the Credentials Provider
Open your authentication configuration.
lib/auth.ts
Import the database helper.
import { connectDB } from "@/lib/mongodb";
Update the authorize() function.
async authorize(credentials) {
if (!credentials?.email || !credentials?.password) {
return null;
}
const db = await connectDB();
const user = await db.collection("users").findOne({
email: credentials.email,
});
if (!user) {
return null;
}
// Password validation will be added in the next article.
return {
id: user._id.toString(),
name: user.name,
email: user.email,
};
}
Instead of checking a hardcoded object, we're now searching the MongoDB database.
How Authentication Works Now
Our authentication flow has improved significantly.
User
│
▼
Login Form
│
▼
Credentials Provider
│
▼
MongoDB
│
▼
Find User
│
▼
Return User
│
▼
Create Session
The authentication logic remains the same, but user data now comes from a real database.
Testing the Database Connection
Before implementing registration, insert a sample document into the users collection using MongoDB Compass, Atlas, or the MongoDB Shell.
Example:
{
"name": "John Doe",
"email": "john@example.com",
"password": "123456"
}
For now, the password is stored in plain text only for testing.
We'll replace it with a hashed password in the next article.
Common Mistakes
If your login doesn't work, check the following:
MONGODB_URIis incorrect.MongoDB server isn't running.
The
userscollection doesn't exist.The email doesn't match any document.
Environment variables haven't been reloaded after editing
.env.local.
Most connection issues are caused by one of these configuration mistakes.
Best Practices
As your application grows, follow these recommendations:
Use a single shared MongoDB client.
Store only the fields you need.
Never expose passwords in API responses.
Always validate user input.
Use indexes on frequently queried fields such as
email.
These practices improve both performance and security.
What's Next?
Our application can now retrieve users from MongoDB, but there's still one major security problem—we're storing passwords as plain text.
In the next article, we'll implement password hashing using bcrypt, securely compare passwords during login, and build a production-ready authentication flow.
📚 NextAuth.js Authentication Series
✅ Part 1 — Introduction
✅ Part 2 — Setup & Configuration
✅ Part 3 — Google OAuth
✅ Part 4 — Credentials Provider
✅ Part 5 — MongoDB Integration ← Current
🔜 Part 6 — Password Hashing with bcrypt


