โ† Back to list

๐Ÿ” Auth.js CredentialsProvider Login Flowโ€Šโ€”โ€ŠWith & Without Server Actions

โ†’ Without Server Action

Ezazul Islam ยท 2025-09-16 20:28 ยท 0 claps ยท 2.5 min read
#authjs #nextjs
Open on Medium โ†—
Wiki topics: ๐ŸŒ ยท Web Development

๐Ÿ” Auth.js CredentialsProvider Login Flow โ€” With & Without Server Actions in Nextjs Application

โ†’ Without Server Action

When you donโ€™t use a server action, you call signIn directly inside your onSubmit function. Since this is a client component, you need to import signIn from โ€˜next-auth/reactโ€™. Hereโ€™s an example:

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

async function onSubmit(data) {

/** you can use formData here instead of data, or make a FormData with new FormData()
  * no problem
  * main concern is, you have to provide the signIn email and password somehow
**/

  const response = await signIn("credentials", {
    email: data.email,
    password: data.password,
    redirect: false,
  });

  if (response?.error) {
    // Invalid credentials
    toast.error("Credentials did not match");
  } else {
    // Login successful
    router.push("/");
  }
}

Points to be noted:

  • Here, signIn does not throw an error.
  • It returns a response object.
  • On failure, the object looks like:
{
  error: "CredentialsSignin",
  code: "credentials",
  ok: true,
  status: 200
}

With these error, do whatever you want. The logic is upto you!!!

โ†’ With Server Action

When you use a server action, you create a server function that calls signIn:

"use server";
import { signIn } from "@auth";

export async function loginWithCredentials(data) {
  return await signIn("credentials", {
    email: data.email,
    password: data.password,
    redirect: false, 
    /**
       * By default, signIn() automatically redirects the user after a successful login.
       * This redirect usually goes to "/" (homepage) or the URL defined in `callbackUrl` if provided.
       * You can set `callbackUrl` to send the user to a specific page, for example:
       *     await signIn("credentials", {
       *       email: data.email,
       *       password: data.password,
       *       redirect: true,
       *       callbackUrl: "/dashboard", // user will go here after login
       *     });
       * Setting `redirect: false` prevents automatic navigation.
       * This allows you to handle the response manually in the client,
       * check if login succeeded or failed, show a toast, and then redirect programmatically:
       * for client component, eg: if (!response.error) router.push("/dashboard");
       * for server component, eg: try{...}catch{toast('Error')}
     **/
  });
}

As it is a server action, you cannot import signIn from โ€˜next-auth/reactโ€™ like before. You should have a auth.js(or anything) file for the configs in the root directory, right? You have it there. Basically you are importing the signIn from there. Although I am assuming you know authjs, but still hereโ€™s an example:

import { MongoDBAdapter } from "@auth/mongodb-adapter";
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import Google from "next-auth/providers/google";
import client from "./lib/db";
import { userModel } from "./models/user-model";

export const {
  handlers: { GET, POST },
  signIn,
  signOut,
  auth,
} = NextAuth({
  session: {
    strategy: "jwt",
  },
  adapter: MongoDBAdapter(client, { databaseName: "myDB" }),
  providers: [
    Credentials({
      credentials: {
        email: {},
        password: {},
      },

      async authorize(credentials) {
        if (credentials == null) return null;
        const user = await userModel.findOne({ email: credentials.email });
        if (user) {
          const isMatch = user.password === credentials.password;
          if (isMatch) {
            return user;
          } else {
            return null;
          }
        } else {
          return null;
        }
      },
    })
  ],
});

Then in your client component:

async function onSubmit(data) {
  try {
    await loginWithCredentials(data);
    /** Login successful
      * You can do whatever you want here, I am redirecting to my homepage
    **/
    router.push("/");
  } catch (err) {
    /** Invalid credentials throw an error here
      * You can do whatever you want here, I am showing a toast
    **/
    toast.error("Credentials did not match");
  }
}

Points to be noted:

  • With server actions, signIn throws a CredentialsSignin error on invalid credentials if returning null from the authorize function.
  • Therefore, try/catch is required to handle failures.

Hope it helped. Thank you for your time.


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
6fe8ff5141be
slug
auth-js-credentialsprovider-login-flow-with-without-server-actions-6fe8ff5141be
url
https://medium.com/@15iezazul/auth-js-credentialsprovider-login-flow-with-without-server-actions-6fe8ff5141be
canonical_url
https://medium.com/@15iezazul/auth-js-credentialsprovider-login-flow-with-without-server-actions-6fe8ff5141be
author_url
https://medium.com/@15iezazul
status
ok
fetched_at
2026-07-17 11:44:46