Open-Assistant icon indicating copy to clipboard operation
Open-Assistant copied to clipboard

Create role field in website User table and be able to seed it

Open fozziethebeat opened this issue 2 years ago • 13 comments
trafficstars

We need a role field in the website's User table. By default any new user should be given the general role.

We also need a seed script that lets us mark one or more users as admins in advance. That seed script should let us configure via an environment variable the set of admins via their auth method (discord or email) and the username they use (their discord username or their email address).

When a user matching this short list signs up, they should automatically be given the admin role.

fozziethebeat avatar Jan 01 '23 12:01 fozziethebeat

Whoever does this should probably review https://next-auth.js.org/tutorials/role-based-login-strategy

fozziethebeat avatar Jan 01 '23 12:01 fozziethebeat

I am looking into this

Jason-Kim1023 avatar Jan 02 '23 01:01 Jason-Kim1023

Great, I'll assign it to you for the time being.

fozziethebeat avatar Jan 02 '23 03:01 fozziethebeat

For the first part of adding role, I believe this change is what the provided resource states is the simple fix, which I updated in my local code: model User { id String @id @default(cuid()) name String? email String? @unique emailVerified DateTime? image String? role String? // New Column accounts Account[] sessions Session[]

tasks RegisteredTask[] }

**this code can be used to have 2 users with admin roles, but can be expanded to more users Step 1 would be: -config.js file that contains something like: process.env.ADMIN_USERS = 'JasonKim#1234', ‘[email protected]’;

Step 2: This code will then in the auth file of the api folder

require('./config');

Same code as before….. New edits:

const authOptions: AuthOptions = { // Ensure we can store user data in a database. adapter: PrismaAdapter(prisma), providers, pages: { signIn: "/auth/signin", verifyRequest: "/auth/verify", // error: "/auth/error", -Will be used later }, session: { strategy: "jwt", }, callbacks: { // This function is called during the session async session(user, account, profile) { // Check if the user should be marked as an admin. const adminUsers = process.env.ADMIN_USERS.split(","); //if conditional for whether or no is or isnt admin user.. if id is found in ADMIN_USERS, then role is set to admin if (adminUsers && adminUsers.includes(user.)) { // Mark the user as an admin. await prisma.user.update({ where: { id: user.id, }, data: { role: "ADMIN", }, }); } //if it isn't found, it will set it to general automatically. else { await prisma.user.update({ where: { id: user.id, }, data: { role: "general", }, }); } }, }, };

export default NextAuth(authOptions);

Jason-Kim1023 avatar Jan 02 '23 07:01 Jason-Kim1023

as of right now looking how to check the discord/email id instead of just the user id.. will look over tomorrow

Jason-Kim1023 avatar Jan 02 '23 07:01 Jason-Kim1023

This looks great! Whenever you're ready prepare a PR and I'll review.

fozziethebeat avatar Jan 02 '23 07:01 fozziethebeat

just for clarification, do you want this process to happen during the session callback so that it checks if a user is an admin depending on whether or not the account parameter in session(user, account) is discord or email and then looks inside the config file to make the judgement of admin role or general role?

Essentially, something like this?

callbacks: {
    async session(user, account) {
      // Check if the user should be marked as an admin.
      const adminUsers = process.env.ADMIN_USERS.split(",");
      if (account && account.providor === "discord") {
        const discordID = account.id;
        const discordUsername = account.username;
        const discordIdAndUsername = `${discordUsername}#${discordID}`;
        if (adminUsers && (adminUsers.includes(discordIdAndUsername))) {
          // Mark the user as an admin.
          await prisma.user.update({
            where: {
              id: user.id,
            },
            data: {
              role: "ADMIN",
            },
          });
        }
      }
      if (adminUsers && (adminUsers.includes(user.email))) {
        // Mark the user as an admin.
        await prisma.user.update({
          where: {
            id: user.id,
          },
          data: {
            role: "ADMIN",
          },
        });
      }
      else {
        await prisma.user.update({
          where: {
            id: user.id,
          },
          data: {
            role: "general",
          },
        });
      }
    },
  },
};

export default NextAuth(authOptions);

or is it at another time like signin callback or signup callback?

Jason-Kim1023 avatar Jan 02 '23 18:01 Jason-Kim1023

I was thinking that upon new account creation we'd check the user's ID against the environment variable. If that matches then we'd update their role value in the User table. From that point on, we just have to make sure the session and token objects have that role value so other parts of the app can make their changes accordingly.

I think this can be done by using one of the Next Auth event callbacks to do the check and then updating the database table.

fozziethebeat avatar Jan 02 '23 23:01 fozziethebeat

The code should be almost the same as what you draft but just in a different callback. Session gets called a lot and shouldn't be making mutations.

fozziethebeat avatar Jan 02 '23 23:01 fozziethebeat

Okay, that thank you for the clarification. Just doing the callback on linkaccount should be fine then since linkaccount for an account is unique. I’ll get on that!

Jason-Kim1023 avatar Jan 03 '23 00:01 Jason-Kim1023

I was thinking that upon new account creation we'd check the user's ID against the environment variable. If that matches then we'd update their role value in the User table.

I don't have a good overview over the exact events happening, but is there something like a "login" event? If we just assign upon account creation (which I assume happens on the very first login), then we can't later easily modify the admin list, when the accounts already exist.

yk avatar Jan 03 '23 07:01 yk

Yup! I can modify the code so that it updates and checks on login instead of account creation. That way if someone is (lets say deleted from the admin list) it can be updated when that user logs in next.

Jason-Kim1023 avatar Jan 03 '23 07:01 Jason-Kim1023

I like that too as the account will exist on our staging database when we dd this support in.

fozziethebeat avatar Jan 03 '23 08:01 fozziethebeat