Access Collection Internally from Hook

default discord avatar
peniswafflexdlast year
2 1

Hey again,

So I have a public facing server that Payload is sitting on, so the API is accessible from anywhere. This I have no problem with, however, one of my hooks sends out an email to an email list collection. I definitely don't want to have my users email addresses accessible publicly, however, I do want them to be able to be created and deleted publicly.

Currently I have some hacky code that uses a fetch request from within the payload hook to pull down the email list and send emails out to it, but this is only possible because that collection can be read publicly.

How do I go about accessing Collection Docs internally?

Here is my current (insecure) implementation:

const emailSubscribers = async ({doc}) => {
    if(doc.notify === true){
        const responseEmail = await fetch(HOST+`/api/emaillist`)
        const emails = await responseEmail.json()
        const responseImage = await fetch(HOST+`/api/media/${doc.featureImage}`)
        const image = await responseImage.json()

        let imageBuffer = await axios.get(image.sizes.feature.url, {responseType: 'arraybuffer'})
        let raw = Buffer.from(imageBuffer.data).toString('base64')
        let base64Image = `data:${imageBuffer.headers["content-type"]};base64,${raw}`
        // console.log(base64Image)
        for(const emailObj of emails.docs) {
            const htmlToSend = HtmlTemplate({
                title: doc.title,
                subtitle: doc.subtitle,
                imageLink: base64Image,
                unsubscribeLink: HOST+"/unsubscribe/"+emailObj.id,
                postLink: WEBSITE+`/posts/${doc.slug}`
            })
            payload.sendEmail({
                from: "User <User@email.com>",
                to: emailObj.email,
                subject: "New Article!",
                html: htmlToSend
            })
        }
            console.log("Subscribers Notified!")
    }
};
  • Selected Answer
    discord user avatar
    jmikrut
    last year

    Hey @peniswafflexd — this is super easily solved actually via a few options.

    In any case, and as you probably know already, you should restrict read access control to any collections that should not be publicly readable. However, once access is restricted, you can:

    1. First authenticate via logging in with a user that should have read access, and then using the returned token to authenticate in your fetch
    2. Enable API Keys on your Users collection(s), generate a key, and use that
    3. Use the Local API to read your restricted docs. By default, access control is bypassed while using the Local API so you won't have any problems. All you have to do is payload.find({ /* options here */ }). This is how you should typically access Payload operations from hooks, because it avoids having to use an HTTP layer and just stays right on your server. Definitely what we would do.

    Do any of these options work? Have you used the Local API yet?

    2 replies
  • default discord avatar
    peniswafflexdlast year

    Wow that was solved super easily!
    Sorry my bad, I assumed the local API was something completely different but that solved it straight away.

    All I needed to do was swap:

     const responseEmail = await fetch(HOST+`/api/emaillist`)
            const emails = await responseEmail.json()

    with

     const emails = await payload.find({
                collection: 'emaillist',
            });

    and it worked straight away!

    I just turned read access off and it works fine now

  • discord user avatar
    jmikrut
    last year

    Hell yeah 👍 the local API is one of my personal favorite parts about Payload. Local API + Hooks = ❤️

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.