Logo

dev-resources.site

for different kinds of informations.

Roles based authentication using Nextauth and next.js

Published at
7/21/2024
Categories
javascript
nextjs
authjs
Author
arindam_roy_382
Categories
3 categories in total
javascript
open
nextjs
open
authjs
open
Author
15 person written this
arindam_roy_382
open
Roles based authentication using Nextauth and next.js

Hello , so if you also wondered around the dark ally of internet searching for your own Auth and roles based solutions but you couldn't find any or maybe you did it's just doesn't work anymore then you are at the right place with the functional code i'll also give the packages version so it would be easier for you guys.

now let's first install all the packages you'll need

  npm install next-auth@beta
  npm install drizzle-orm zod react-hook-form
Enter fullscreen mode Exit fullscreen mode

now let's setup the auth providers for nextAuth will create a file in our

lib/auth/index.ts

in this file we are gonna use the credentails provider because by default OAuth doesn't give us any roles back but we are also gonna see how to use oAuth to assign roles

  export const { handlers, signIn, signOut, auth } = NextAuth({
 adapter: DrizzleAdapter(db),
  providers: [
    Credentials({
      name: "credentials",
      credentials: {
        email: {
          type: "email",
          label: "Email Address",
          placeholder: "Email Address",
        },
        password: {
          type: "password",
          label: "Password",
        },
      },
      async authorize(credentials) {
        const { email, password } = await signInSchema.parseAsync(credentials);

        const user = await db
          .select()
          .from(users)
          .where(eq(users.email, email))
          .execute()
          .then((res) => res[0]);

        if (!user || !user.password) return null;

         const isValidPassword = await bcryptjs.compare(password, user.password);

         if (!isValidPassword) return null;

        return {
          id: user.id,
          name: user.name,
          email: user.email,
        };
      },
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,

      profile(profile: GoogleProfile) {
        return { ...profile, role: "user" };
      },
    })
  ],
});
Enter fullscreen mode Exit fullscreen mode

Maybe it's a good time to mention that i'm using postgres and drizzle ORM to save and retrieve this information from DB.

we are using drizzle adapter for it you can installed it using

npm install drizzle-orm @auth/drizzle-adapter
npm install drizzle-kit --save-dev
Enter fullscreen mode Exit fullscreen mode

you can find the drizzle suited schema in here link for the auth to work . now we just have to use this handler in the api routes to make it work.

import { handlers } from "@/lib/auth";

export const { GET, POST } = handlers;
Enter fullscreen mode Exit fullscreen mode

now the auth works but there's no rolese yet. first we'll modify the drizzle schema and then our nextAuth options.

Remember this can be a simple field as roles in the users table which holds a string value . but I made it this way so i can make as many roles as i want and add permission to it

export const roles = pgTable("roles", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => createId()),
  name: text("name").notNull(),
  description: text("description"),
});

export const permissions = pgTable("permissions", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => createId()),
  name: text("name").notNull(),
  description: text("description"),
});

export const rolePermissions = pgTable("role_permissions", {
  roleId: text("roleId").references(() => roles.id, { onDelete: "cascade" }),
  permissionId: text("permissionId").references(() => permissions.id, {
    onDelete: "cascade",
  }),
});

export const userRoles = pgTable("user_roles", {
  userId: text("userId").references(() => users.id, { onDelete: "cascade" }),
  roleId: text("roleId").references(() => roles.id, { onDelete: "cascade" }),
});
Enter fullscreen mode Exit fullscreen mode

now we need to modify the NextAuthOption so roles and permission get included in the user session.

first we'll define the callback functions for getting the roles ourselves .

 callbacks: {
    async jwt({ token, user }) {
      if (user && user.id) {
        const { role, permissions } = await getUserRoleAndPermissions(user.id);
        token.role = role;
        token.permissions = permissions;
      }
      return token;
    },
    async session({ session, token }) {
      if (token && session.user) {
        session.user.id = token.id;
        session.user.role = token.role;
        session.user.permissions = token.permissions;
      }
      return session;
    },
  },
Enter fullscreen mode Exit fullscreen mode

The getRolesandPermission function does exactly as it sounds it uses drizzle to query roles and permission from db . By default this alone won't work we also need to make some changes in the types.

declare module "next-auth" {
  interface Session {
    user: {
      id: string;
      role: string;
      permissions: string[];
    } & DefaultSession["user"];
  }
}

declare module "next-auth/jwt" {
  interface JWT {
    id: string;
    role: string;
    permissions: string[];
  }
}
Enter fullscreen mode Exit fullscreen mode

now by accessing the session we can get roles and permission. and by using this you can block the user at page level or by using middleware a whole route group you can protect.

this method can be really useful in a multi tenant sass may be you don't wanna save your user elsewhere this is a perfect solutions. Thank you for reading this

authjs Article's
30 articles in total
Favicon
Authentication System Using NodeJS
Favicon
Add Authjs to Next.js 15 app router with GitHub Authentication
Favicon
Master Authentication with Auth.js, Next.js, and PostgreSQL: A Comprehensive Guide
Favicon
Nuxt Authorization: How to Implement Team Role-Based Access Control in Nuxt 3
Favicon
Mastering Authentication in Next.js: A Step-by-Step Guide to GitHub Login with Auth.js
Favicon
User Authentication with Auth.js in Next.js App Router
Favicon
Lucia Auth is getting deprected
Favicon
Integrating GitHub Authentication with NextAuth.js: A Step-by-Step Guide
Favicon
Simple Next.js Magic Link JWT Authentication with Prisma, PostgreSQL, and Resend
Favicon
Password Authentication with Auth.js in Astro and Customizing Session Information (auth-astro)
Favicon
Basic Authentication for Nuxt.js (JSON Web Token + Local Storage)
Favicon
Implementing Federated Sign-Out with Auth.js in Next.js 14 App Router
Favicon
Integrating LinkedIn Authentication with NextAuth.js: A Step-by-Step Guide
Favicon
Implementing auth.js v5 with Prisma and Supabase in Next.js
Favicon
Auth, OAuth, and Auth0: What is what?
Favicon
JWT Authentication and Cookie Management in Web Applications
Favicon
๐Ÿš€ Exciting News!
Favicon
Data Persistence (Cookies, Sessions, Tokens, LocalStorage and SessionStorage)
Favicon
Fashion website
Favicon
The Firebase Shortcut: Simplifying Next.js Authentication
Favicon
Authentication system in Next.Js using Auth.js
Favicon
Roles based authentication using Nextauth and next.js
Favicon
Authentication & Authorization
Favicon
Top User Authentication Tools for Developers
Favicon
Comprehensive Guide to SvelteKitAuth: Secure Authentication for SvelteKit Apps
Favicon
Building a Secure OTP-based Login System in Next.js
Favicon
Implementing Secure Authentication in Next.js with JWT and MongoDB. Protect Routes using middleware
Favicon
Next.js 14 and NextAuth v4 : Credentials Authentication A Detailed Step-by-Step Guide
Favicon
Building a Secure OTP-based Login System in Next.js
Favicon
Web3Auth(ๆฌกใฎjs)ใ‚’ไฝฟ็”จใ—ใŸXRP Ledgerใ‚ขใ‚ซใ‚ฆใƒณใƒˆใฎไฝœๆˆ:ใ‚นใƒ†ใƒƒใƒ—ใƒใ‚คใ‚นใƒ†ใƒƒใƒ—ใ‚ฌใ‚คใƒ‰

Featured ones: