Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Multiple user collections

default discord avatar
nlvogellast year
7

I’m trying to create a second user collection called

customers

but I’m having some issues getting it working. I’m following the auth example in the GitHub and it works fine when I’m logged into an admin user.



My use case is I’d like to gate content based on subscription tier, and I don’t want to include customers in my main user collection where my editors and admins are. The customers should be able to follow a different login flow and shouldn’t have access to the admin panel.



Has anyone implemented something like this?

  • default discord avatar
    rilromlast year

    The way I'd normally approach this is a single user collection that contains a

    role

    field (e.g.

    admin

    ,

    customer

    ).



    I'd then make sure to set the

    admin

    access control to only allow the

    admin

    role to access the CMS (

    https://payloadcms.com/docs/access-control/collections#admin

    )



    This means if a

    customer

    role logs in through your custom login flow (or for some reason at

    /admin/login

    ) and then attempted to visit

    /admin

    , they would be shown an unauthorized screen.



    If you definitely want to have separate collections, could you elaborate on what isn't working for you? It should be possible.

  • default discord avatar
    nlvogellast year

    I suppose I could have the customer role and then an option tier select when role is customer, but that does keep everything together in the same collection, which I don’t love.



    What’s not working: I think the user isn’t persisting after hitting the login route. I can create a user, and I see the new customer in my collection, but when I try to login with that user, it returns null. Looking at the auth example, there is a

    useState

    that sets user and returns user. When I log the customer after the api is hit, I get the customer info, but when I try to log

    user

    after using

    setUser

    it returns null.



    When I have my auto login set with an admin user, I can see and access all the account info im rendering on the front end, but after I disable that and try to login with a user from my customers collection, I just get stuck in a loop of “you must login to see your account”



    For easy reference, here’s the auth example:

    https://github.com/payloadcms/payload/tree/main/examples/auth

    some things are dated in it (like types from payload/auth), but I’ve fixed all that.



    The auth example does use the user collection, but I updated all references to my Customer type and api routes



    @127418710519578624

    I’ve been thinking about how you said you’d handle this and I think that might be the best approach. My primary concern was that one collection with many customers mixed in with admins would be too much to manage. Do you see that as an issue? I could always setup a custom component to filter each role in the table view if I really wanted to.



    Maybe I’m overthinking why I’d want a second user collection

  • default discord avatar
    mikecebullast year

    I wonder if you could easily customize the collection filter component to add a toggle button for admins and customers, then it won't feel so tied together.

  • default discord avatar
    nlvogellast year

    I'm starting to think that my approach actually wasn't wrong and the way auth is done in the example isn't working right. I switched everything back to be a single user collection and I still can't login. I can create no problem, though.

  • default discord avatar
    adek1449last year

    I'm not sure if you're looking for something like this:

    https://www.youtube.com/watch?v=AEyR91PSpoI

    Seems the same use case

  • default discord avatar
    norbert8615last year

    Hey. I'm not an expert, I came here mostly to read rather than write but I implemented something similar and had a similar problem during development. In my case, the issue occurred because the payload for both collections returned an httpOnly cookie called

    payload-token

    . I don't remember my exact flow, but in some cases, a token was generated for the wrong collection.



    For example, if you log in to the admin panel (UsersCollection) and then try to access /api/customers/me (CustomersCollection), it won’t work. To resolve this, clear your cookies before logging in or log out from the admin panel before attempting to log in to the customers collection.



    I'm not sure what your configuration is, but as far as I understand, you have two auth collections. One of them is the users collection, which is assigned to the admin.user property in your payload.config, and the other is CustomersCollection, which is imported into the collections array like this:



    export default buildConfig({
      admin: {
        user: UsersCollection.slug,
        // ...
      },
      // ...
      collections: [
        UsersCollection,
        CustomersCollection
      ]
    });


    If you don’t want CustomersCollection to have access to the admin panel, simply add

    admin: () => false

    in the access configuration of the collection. Check out my CustomersCollection config:



    export const CustomersCollection: CollectionConfig = {
      slug: 'customers',
      auth: {
        tokenExpiration: 60 * 60 * 12, // 12h
        maxLoginAttempts: 30,
        lockTime: 60 * 60 * 1, // 1h
      },
      access: {
        admin: () => false, // Disables admin panel for this collection
        create: () => true, // Allows registering users 
      },
      admin: {
        // ...
      },
      fields: collectionFields,
    };


    Make sure that if you want to log in as a customer, you need to call /api/customers/login. If you’re using fetch to make API calls, remember to add

    { credentials: "include" }

    to your requests, like in this example:



    fetch("/api/customers/login", {
      method: "POST",
      credentials: "include", // <- this
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email: "user", password: "pass" })
    });


    If you don’t include this, the cookie won’t be saved. As a result, when you later call collection APIs, your user will not be visible in req.user within hooks and access control functions.



    Then, if you want to verify whether a customer has access to the requested resource, you can check the user collection in req.user, like this:


    async ({ req }) => {
      if (!req.user || req.user.collection === 'users') return true;
      console.log(req.user.collection); // should print 'customers'
      if (userHasAccess) return true;
      return false;
    };
  • default discord avatar
    nlvogellast year

    It's definitely got to be something with cookies then. I'm able to login to only a single account in Chrome, but nothing in Safari where I've done the majority of my development. Opening incognito windows don't help, though, which is strange.



    I'll check the video out and see if it helps me understand what I'm doing wrong here.



    @561632198399098880

    this is actually exactly how I wanted to do this. Thank you for sharing!



    Mentioned the wrong person, oh well 😂

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.