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.

How to handle authentication on custom API routes

default discord avatar
mvdvelast year
13

I have one additional API route which starts an import proces. The route is configures in the global Payload config:



    express: {
        postMiddleware: [importAccess],
    },
    endpoints: [
        {
            path: "/import/run/:collection",
            method: "get",
            handler: importHandler,
        },
    ],


Most works as expected, but i can't seem to get access control working within the middleware or route itself. What i would like to do is call a generic "isAdmin" function (which i already use in other places) on an user object. But the user variable within the request is always undefined. A workaround was loading the import global collection which as access control on it. According to the documentation, access control should be invoked when using req.payload.findGlobal but this is not the case. The collection object is always returned when calling the custom API route. Calling the normal API route for this collections results in a 403 error as expected.



What is the correct way to handle this? Thanks.

  • default discord avatar
    notchrlast year

    Did you call payload.authenticate() after payload.init()?



    undefined users in the cb seem related to that common issue



    https://payloadcms.com/docs/authentication/using-middleware#using-the-payload-auth-middleware

    router.use(payload.authenticate); 
  • default discord avatar
    mvdvelast year

    Ah, i will test that, the official documentation states that authentication is always invoked on req.payload.find

    https://payloadcms.com/docs/rest-api/overview#custom-endpoints

    There seems to be a type error: throw new TypeError('Router.use() requires a middleware function')



    Also, i am configuring my routes within the payload config, not directly in Express, you should say the authentication is already invoked.

  • default discord avatar
    notchrlast year

    Hmmm



    I'm looking at

    https://payloadcms.com/docs/rest-api/overview#custom-endpoints

    They say that the req object applies access control

  • discord user avatar
    dribbens
    last year

    As you guys already pointed out, the authentication middleware should be called for you before your custom

    endpoints

    are called.



    Since you are using

    postMiddleware

    that is going to be called at the very end, but it seems to me you would want to get your access control handled first as

    preMiddleware
  • default discord avatar
    mvdvelast year

    This is strange, it worked for a couple of minutes (had a user object within the response) and now its gone again...

  • discord user avatar
    dribbens
    last year

    To simplify why you have you, you could do this instead:


    handler: [importAccess, importHandler],
  • default discord avatar
    mvdvelast year
    @969226489549713438

    , i also tested with preMiddleware but that made no difference.



    I will try that

  • discord user avatar
    dribbens
    last year

    Yeah, it shouldn't matter



    well...



    preMiddleware

    means you won't have

    req.user

    assigned yet



    postMiddleware

    should have

    req.user

    as well as the suggestion I made with the

    handler: [accessImport, importHandler]

    . This is probably not going to fix your issue.

  • default discord avatar
    mvdvelast year

    Thats sound logical.



    It seems to work with the handler and middleware together. Will investigate what went wrong there.

  • discord user avatar
    dribbens
    last year

    That is interesting! I'm glad it works for you. There could be a bug in globals postMiddleware or something else going on that is specific to your project.

  • default discord avatar
    swnzllast year

    I think there might be a misunderstanding here. The docs say:


    req will have the payload object and can be used inside your endpoint handlers for making calls like req.payload.find() that will make use of access control and hooks.

    I think you have to read it like this: "

    can

    be used for making calls that can make use of access control and hooks"


    From how I understand it, there is no magic that automatically tells the payload instance what the currently processed

    req

    and subsequently

    req.user

    object is. So in order to make use of access control for the local api you have to pass in the

    req

    object to

    payload.find

    which is also what for example the find handler does:

    https://github.com/payloadcms/payload/blob/master/src/collections/requestHandlers/find.ts#L24e

    Just realized the handler is not actually itself using the local api 🤦‍♂️. Doesn't change the matter, though. You'll have to provide

    req

    and

    overrideAccess:false

    to local api for access control mechanisms to be used.

  • default discord avatar
    ssyberglast year
    @987641835751096320

    I have a similar question, I'd trying to persist

    req

    attributes from my custom endpoint (in this case a gql query) but they disappear in lower level local API calls. I tried passing

    req

    into the

    find

    call but got an error. Were you able to solve this?

  • default discord avatar
    swnzllast year
    @778799229988110337

    you might want to add another thread with some more context for this. Sounds like there's something else going on, I've never had issues using the

    req

    object.

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.