Home > Web Front-end > JS Tutorial > body text

Roles based authentication using Nextauth and next.js

WBOY
Release: 2024-07-22 10:15:31
Original
722 people have browsed it

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
Copy after login

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" };
      },
    })
  ],
});
Copy after login

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
Copy after login

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;
Copy after login

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" }),
});
Copy after login

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;
    },
  },
Copy after login

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[];
  }
}
Copy after login

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

The above is the detailed content of Roles based authentication using Nextauth and next.js. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template