Smart action returns 403 for some users

Hello there Forest admin folks,
We’ve currently got a weird issue with one of our smart actions,

Expected behaviour

We’re currently expecting a smart action with endpoint /forest/actions/mark-as-ready to work consistently for all users.

Actual behaviour

This smart action endpoint seems to work for most users: however, for some users it doesn’t seem to work at all. For a particular user with the following config:

  • role: Programme Team
  • permission to use the action in Production

You can see below the request made by their browser:
curl 'https://prodhub-api.thenational.academy/forest/actions/mark-as-ready' \ -H 'authority: prodhub-api.thenational.academy' \ -H 'sec-ch-ua: "Chromium";v="94", "Microsoft Edge";v="94", ";Not A Brand";v="99"' \ -H 'accept: application/json' \ -H 'content-type: application/json' \ -H 'authorization: Bearer bearer-token-here' \ -H 'sec-ch-ua-mobile: ?0' \ -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38' \ -H 'sec-ch-ua-platform: "Windows"' \ -H 'origin: [https://prodhub.thenational.academy](https://prodhub.thenational.academy/)' \ -H 'sec-fetch-site: same-site' \ -H 'sec-fetch-mode: cors' \ -H 'sec-fetch-dest: empty' \ -H 'referer: https://prodhub.thenational.academy/' \ -H 'accept-language: en-GB,en;q=0.9,en-US;q=0.8' \ -H 'cookie: oakData={%22userId%22:%22a9f4803d-e544-4afb-a018-884d17220dbd%22}; _ga=GA1.2.545874265.1633938139; _gid=GA1.2.1630940283.1633938139; _hjid=fba5a2d5-99e3-4fa8-927c-b16d2a9b6cd3; hubspotutk=fb7c4ec47c538325691748c10c7cc50c; __hssrc=1; intercom-id-fx7fosz0=a3e3cef9-c21e-4e5b-ac9f-c2b6ad53bb91; intercom-session-fx7fosz0=; ajs_anonymous_id=c474dacc-610f-42bd-b85f-1903fcc4a7da; _fbp=fb.1.1633943978636.569209688; ajs_user_id=56032; _cioid=56032; _hjAbsoluteSessionInProgress=0; __hstc=83091209.fb7c4ec47c538325691748c10c7cc50c.1633938138977.1633938138977.1633963105061.2; cookie-consents=%5B%5B%22metomic-consented-pol%3A3c779fd2-9d6b-4613-8eed-e746cb669d7e%22%2C%22%7B%5C%22enabled%5C%22%3Atrue%2C%5C%22version%5C%22%3A%5C%223.0.0%5C%22%7D%22%5D%2C%5B%22metomic-consented-pol%3A68beb01a-65f3-481d-b9db-be05ad95c5a1%22%2C%22%7B%5C%22enabled%5C%22%3Atrue%2C%5C%22version%5C%22%3A%5C%223.0.0%5C%22%7D%22%5D%2C%5B%22metomic-consented-pol%3A8fd55105-adc2-4c33-baf9-a8d75961eeff%22%2C%22%7B%5C%22enabled%5C%22%3Atrue%2C%5C%22version%5C%22%3A%5C%222.0.0%5C%22%7D%22%5D%2C%5B%22metomic-consented-pol%3Ab109d120-ec88-4dd7-9f6e-fc67ab6f0ffb%22%2C%22%7B%5C%22enabled%5C%22%3Atrue%2C%5C%22version%5C%22%3A%5C%223.0.0%5C%22%7D%22%5D%5D; __hssc=83091209.2.1633963105061; __cf_bm=3nkeokBwWheDHHhVpHYZz_9Tb6kCvb8lI6aJC7xYpyc-1633964015-0-ARvv9QYxIwGXl72k5u4SZB7GGpLwpzE/O7AIWXEICvr/o093lIRd+JlBOmvXNlJHXEdDU0G/3n9hbeR6N7dgxtd+GH+tb/4T1MdL0CLP8M2y8JyBPpCAL1XEgIQouVI5XW9fFY8Pfm3Urw+e6hqx2dwBqiaeDfvdyVhOJA1UOgsc; _gat=1' \ --data-raw '{"data":{"attributes":{"values":{},"ids":["7562"],"collection_name":"lessons","parent_collection_name":null,"parent_collection_id":null,"parent_association_name":null,"all_records":false,"all_records_subset_query":{},"all_records_ids_excluded":[],"smart_action_id":"lessons-Mark@@@as@@@ready"},"type":"custom-action-requests"}}' \ --compressed

Failure Logs

In dev tools, this endpoint currently responds with 403 stating that it is Forbidden.
I’ve also double checked Cloudflare and can confirm that cloudflare is not challenging or blocking this request.

Context

Please provide any relevant information about your setup.
image

Hello @Mitchell_Lloyd,

Thanks you for your message.

Can you find a pattern in which users cannot use this Smart Action? All from team “Programme Team”? Or is this random?
Does it happen that the same user can call the action and later cannot?

Could you please share the logs from your Forest Agent?

Thank you

Hi @Guillaume_Deslandes ,
Thank you for your help
All the users that cannot use this Smart Action have the “Programme Team” role and a permission level of “user”.
No they’ve never been able to call the “Mark as ready” smart action.

When you mean Forest agent do you mean our hosted backend ?
Cheers Mitch

@Mitchell_Lloyd,

If you see a call that should be the case, but can you double check in the “project settings”, “roles” tab, if the “mark as ready” action has its “trigger” permission set? If yes, can you try to unset it, and set it again to see if a permission was properly saved?

On the other point, yes I meant your hosted backend, sorry that was not clear.

Maybe the log will point us the source of the permission error.

You can start it with DEBUG=* node ./server.js to activate more logs if necessary.

Thank you

Morning @Guillaume_Deslandes ,
I’m only getting something like this at the moment:


in our cloud logs - so very little information.
I’ve re-produced the issue in my staging environment as below:
Strangely though we have another smart action called Mark as draft - and this works just fine. See the curl for the working action below.

curl 'https://production-hub-staging-3cpfjmgzfa-nw.a.run.app/forest/actions/mark-as-draft' \
  -H 'authority: production-hub-staging-3cpfjmgzfa-nw.a.run.app' \
  -H 'sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer eaJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjQ3NzE4IiwiZW1haWwiOiJtaXRjaGVsbC5sbG95ZEB0aGVuYXRpb25hbC5hY2FkZW15IiwiZmlyc3ROYW1lIjoiTWl0Y2hlbGwiLCJsYXN0TmFtZSI6Ikxsb3lkIiwidGVhbSI6IkVuZ2luZWVyaW5nIiwicmVuZGVyaW5nSWQiOjc1NzE1LCJpYXQiOjE2MzQxMTk0NDcsImV4cCI6MTYzNDEyMzA0N30.6g7UafB80Lvj4HqKZARwGGNtgXDXOCtmMfG2BwFfuyA' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36' \
  -H 'content-type: application/json' \
  -H 'origin: https://app.forestadmin.com' \
  -H 'sec-fetch-site: cross-site' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-dest: empty' \
  -H 'referer: https://app.forestadmin.com/' \
  -H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
  --data-raw '{"data":{"attributes":{"values":{},"ids":["4","41"],"collection_name":"lessons","parent_collection_name":null,"parent_collection_id":null,"parent_association_name":null,"all_records":false,"all_records_subset_query":{"fields[lessons]":"id,ingestId,shortCode,title,introText,slug,teacher,unsigned video,signed video,slidesUrl,hasCopyrightMaterial,copyrightHolder,worksheetUrl,worksheetDownloadUrl,exitQuizUrl,createdAt,updatedAt,classroom,teacher_hub,slides_id,worksheet_download_id,worksheet_id,worksheetHasEmbeddedMedia,isSensitive,cohort,state,slides_status,worksheet_status,disciplinaryKnowledge,equipment,guidanceDetails,guidanceWarnings,subject,lessonContent1,lessonContent2,lessonContent3,lessonContent4,lessonContent5,lessonSkills,worksheet_download_status,lessonVocabulary,substantiveKnowledge,supervisionLevel,is_in_live,current_status","fields[teacher]":"preferredNameForProfile","fields[unsigned video]":"ingestId","fields[signed video]":"ingestId","fields[cohort]":"id","page[number]":1,"page[size]":15,"sort":"createdAt","filters":"{\"field\":\"state\",\"operator\":\"equal\",\"value\":\"Draft\"}","searchExtended":0,"timezone":"Europe/London"},"all_records_ids_excluded":["3","3864","8020"],"smart_action_id":"lessons-Mark@@@as@@@draft"},"type":"custom-action-requests"}}' \
  --compressed

and compare that wit the curl for the action that isn’t working:

curl 'https://production-hub-staging-3cpfjmgzfa-nw.a.run.app/forest/actions/mark-as-ready' \
  -H 'authority: production-hub-staging-3cpfjmgzfa-nw.a.run.app' \
  -H 'sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer eaJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjQ3NzE4IiwiZW1haWwiOiJtaXRjaGVsbC5sbG95ZEB0aGVuYXRpb25hbC5hY2FkZW15IiwiZmlyc3ROYW1lIjoiTWl0Y2hlbGwiLCJsYXN0TmFtZSI6Ikxsb3lkIiwidGVhbSI6IkVuZ2luZWVyaW5nIiwicmVuZGVyaW5nSWQiOjc1NzE1LCJpYXQiOjE2MzQxMTk0NDcsImV4cCI6MTYzNDEyMzA0N30.6g7UafB80Lvj4HqKZARwGGNtgXDXOCtmMfG2BwFfuyA' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36' \
  -H 'content-type: application/json' \
  -H 'origin: https://app.forestadmin.com' \
  -H 'sec-fetch-site: cross-site' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-dest: empty' \
  -H 'referer: https://app.forestadmin.com/' \
  -H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
  --data-raw '{"data":{"attributes":{"values":{},"ids":["4","41"],"collection_name":"lessons","parent_collection_name":null,"parent_collection_id":null,"parent_association_name":null,"all_records":false,"all_records_subset_query":{"fields[lessons]":"id,ingestId,shortCode,title,introText,slug,teacher,unsigned video,signed video,slidesUrl,hasCopyrightMaterial,copyrightHolder,worksheetUrl,worksheetDownloadUrl,exitQuizUrl,createdAt,updatedAt,classroom,teacher_hub,slides_id,worksheet_download_id,worksheet_id,worksheetHasEmbeddedMedia,isSensitive,cohort,state,slides_status,worksheet_status,disciplinaryKnowledge,equipment,guidanceDetails,guidanceWarnings,subject,lessonContent1,lessonContent2,lessonContent3,lessonContent4,lessonContent5,lessonSkills,worksheet_download_status,lessonVocabulary,substantiveKnowledge,supervisionLevel,is_in_live,current_status","fields[teacher]":"preferredNameForProfile","fields[unsigned video]":"ingestId","fields[signed video]":"ingestId","fields[cohort]":"id","page[number]":1,"page[size]":15,"sort":"createdAt","filters":"{\"field\":\"state\",\"operator\":\"equal\",\"value\":\"Draft\"}","searchExtended":0,"timezone":"Europe/London"},"all_records_ids_excluded":["3","3864","8020"],"smart_action_id":"lessons-Mark@@@as@@@ready"},"type":"custom-action-requests"}}' \
  --compressed
{"errors":[{"status":403,"detail":"Forbidden"}]}%

I don’t really see a difference between them - I’ve also double checked the permissions and both smart actions are enabled and have the permission to update the collections they are triggered on.
Here are the permissions for the Programme Team role just to be clear:

@Mitchell_Lloyd,

Indeed both are the same, except for the Smart Action identifier, which is expected.

Can you check the definition of the Smart Actions in your code?
Both should be defined in files in your forest/ directory.

I’m trying to get if the 403 error comes from how Forest Admin handles the request, or from your business code.

Could you also tell me on which model these actions act? I’ll look into what is stored on our end.

Thank you for your patience.

Hi @Guillaume_Deslandes ,
Here is the definition of our smart actions ( on the lessons ):

Both Mark as draft and Mark as ready will update the state field on lessons to "draft" and "ready", respectively. They should also create a loggedAction and a lessonAudit record ( created in a beforeUpdate hook ) - this is part of our audit trail process. The permissions to update a lesson and create a loggedAction and lessonAudit record have all been enabled in both Production and Staging.

It is also worth noting that the Mark as ready smart action and endpoint is also used by other collections too - assets, videos and quizzes. Sometimes if I add permissions to trigger the smart action on assets then it starts working for lessons too.

Weirdly, my colleague and I have seen this action ( Mark as ready ) work and stop working throughout the day. We’ve tried to make small updates to permissions on unrelated collections - but the permissions seem to take some time before they take effect so it is impossible to know exactly what is working and what is not. But this only works sometimes.

Thankyou for your help so far - really appreciate it.

Hello @Mitchell_Lloyd,

Sorry for the lag in my answer.

If I understand properly, you are reusing the code for the SmartAction with multiple collections via the same endpoint.
I thing that can cause issues with the way we handle permissions.

Could you try to duplicate the SmartAction code, use a dedicated endpoint for each action on each collection, and see if things get better?

Hope this helps.

Hey @Guillaume_Deslandes ,
That worked for us :raised_hands:
We basically had 3 different “Mark as ready” smart actions declared in the /forests directory but they were all sharing the same endpoint.
I just created more endpoints - /forest/actions/mark-as-ready became /forest/actions/assets/mark-as-ready etc for each relevant collection. Now it works fine - thankyou for your help!

@Mitchell_Lloyd

Great news. Thank you for your feedback.