Monthly user access review report, ready for your auditor
On the first business day of each month, every organization gets reviewed for who has access and at what level, then the write up lands in Slack.
On the first business day of every month at 7am, produce a written user access review pack I can hand directly to an auditor. Use a cron trigger. Because the first business day moves around, schedule the trigger to fire at 7am on the 1st, 2nd and 3rd of each month, and have the workflow stop immediately unless today is genuinely the first business day of the current month, skipping Saturdays and Sundays. That way exactly one review runs per month no matter which day the month starts on.
Start by pulling every customer organization with WorkOS List Organizations. The WorkOS list endpoints are cursor paginated and return only 10 records by default, so request the maximum page size of 100 and keep following the list_metadata.after cursor until it comes back null. If you stop after the first page you will silently review a fraction of the account and the whole pack becomes misleading.
Then, for each organization, gather WorkOS List Organization Memberships to see who belongs to it and what role they hold, WorkOS List Users to resolve each member into a real person with an email address and account status, and WorkOS List Invitations to catch invites that were sent but never accepted. Page every one of these calls the same way, all the way to the end of the cursor. Pace the per organization loop rather than firing everything at once: some WorkOS resources are rate limited as tightly as 4 requests per second, and a 429 response carries a Retry-After header telling you how many seconds to wait, so honor it with backoff.
Write a review document that stands entirely on its own, because the reader is an auditor with no context on our systems and no access to WorkOS. Open with the review period, the date and time it ran, what was in scope (every customer organization in WorkOS), and a sign off line for the reviewer. Follow with one section per organization listing each member, their email address, their role and their membership status. Give admin level memberships their own dedicated section lifted out of the per organization detail, since elevated access is the first thing a reviewer looks for. Add a section for pending invitations older than 14 days showing the invited email, the organization and how many days it has been outstanding.
Close the document with a revocation candidates section covering anything that looks like it should be removed: inactive or suspended memberships that still hold access, invitations left hanging well past the threshold, admin access in organizations that realistically need only one or two admins, and accounts whose email domain does not match the organization they sit in. State plainly why each one is listed. Keep the tone factual and plain, with no marketing language and no speculation beyond what the data actually supports. Where a section found nothing, say so explicitly rather than leaving it empty, so the reader can tell the difference between a clean check and a check that never ran. Keep the structure identical every month so consecutive reviews can be compared side by side.
Create the report with Google Docs Create Document, titling it 'User Access Review: <Month> <Year>', then write the body in with Google Docs Batch Update Document. Batch Update is atomic, so if any single request in the batch is invalid the entire update is rejected and you are left with an empty document. Build the content carefully and insert it in ordered batches, keeping in mind that each insert shifts the character indexes of everything after it. Confirm the document actually contains the review before moving on.
Finally, post the document link to our compliance channel with Slack Send a Message, together with a two line summary. The first line covers the scale of the review: organizations reviewed, total people with access, and how many of those are admins. The second line covers what actually needs attention: how many invitations are stale and how many revocation candidates were found, naming the most serious one. If nothing needs attention, say that outright. Keep the message short, since the document is the real artifact.
Example output
What does this prompt do?
- Runs on the first business day of every month and collects who currently has access to each customer organization, along with the role they hold.
- Groups everything by organization and pulls admin level access into its own section, since that is the first thing a reviewer looks for.
- Flags invitations that have been sitting unaccepted for more than 14 days, and lists anything that looks like it should be revoked, with a reason for each.
- Writes the whole review into a Google Doc that reads on its own, then posts the link to your compliance channel with a two line summary of what needs attention.
What do I need to use this?
- A WorkOS account containing the organizations and people you want reviewed
- A Google account that can create and edit documents
- A Slack workspace, and the channel where compliance updates get posted
- The name of whoever signs off on the review, if you want a sign off line in the document
How can I customize it?
- Change the cadence or the time: quarterly instead of monthly, or later than 7am.
- Change the 14 day threshold for stale invitations to match whatever your own policy says.
- Add your own revocation rules, for example flagging anyone whose email domain does not match the organization they belong to.
- Send the summary to more than one channel, or to a private channel that only the compliance team can see.
FAQs
Will this remove anyone's access automatically?
What does the auditor actually receive?
What counts as a stale invitation?
Does this work if we have a lot of organizations?
What happens if a section has nothing to report?
Related templates
When your flight moves, your calendar times get corrected automatically and you get a Slack note naming the meetings you're about to miss.
Every 15 minutes, forwarded phishing reports get traced back to the server that really sent them, with a verdict in Slack and the worst senders reported.
Every weekday at 7am, sign in to the tender portals you track, filter new notices against your bid criteria, and open a deal for the ones worth chasing.
Every Monday, rank the week's matches by expected demand, put the big ones on your venue calendar, and post a rota-ready summary to Slack.
Every Tuesday we pull your best new reviews, draft social captions, email testimonials and product page quotes, then stage them in Notion for approval.
Every weekday morning, unfulfilled orders get an address check: harmless typos fixed automatically, risky addresses held with a note to the customer.
Stop rebuilding your access review in a spreadsheet every month.
Let it run on the first business day of the month and hand the finished document straight to your auditor.