Skip to content

Automation  ·  IT and security

How to build access request and approval

An access review finds people holding permissions granted for a project that ended last year. Here is how requests that expire actually works, the prompts that build it, and what running it demands.

Built with Tray Headless

  1. System Slack
  2. Step Resolve owner
  3. Step Approve
  4. Step Grant with expiry
  5. System Okta
Also Vanta Jira

Every grant carries an expiry by default, and the review evidence is produced as a by-product, not assembled the week before an audit.

The short answer

What is access request and approval?

Access request and approval is four parts: routing to the person who owns the system instead of to a shared queue, an expiry on every grant by default instead of on request, automated provisioning and revocation so the record matches reality, and access review evidence produced as a by-product. The common failure is permanence. A grant with no end date is a permanent grant, and the access review that finds it a year later is doing work the request should have prevented.

What matters here

  • Default every grant to an expiry. Permanent should be a deliberate exception with a reason, not the shape everything takes.
  • Route to the person who owns the system, not a shared IT queue. Only the owner knows whether the access is reasonable.
  • Provision and revoke through the integration. A ticket saying access was removed is not evidence that it was.
  • Ask for the business reason, and keep it. It is the only thing that makes a review decision possible a year later.
  • The best report is people who left and still hold access. It should be zero and it never is on the first run.

Who this is for

You run IT operations or security. Access is requested in tickets, approved by whoever picks it up, granted by hand, and reviewed once a year in a spreadsheet nobody enjoys.

How it works in practice

The sequence, from somebody needing access to the access review being answerable.

  1. 1

    The request is raised where people already are

    Chat or a short form. A portal nobody has bookmarked produces requests by direct message instead.

  2. 2

    The system owner approves, not a shared queue

    Resolved from a register, with a deputy for anybody away, because a request waiting three days becomes a workaround.

  3. 3

    An expiry is set by default

    Thirty, sixty or ninety days depending on sensitivity. Permanent requires a reason and a second approver.

  4. 4

    Provisioning happens through the integration

    Not a ticket asking somebody to do it. The grant and the record are the same event.

  5. 5

    The holder is warned before expiry

    With one click to extend and a reason required, so renewal is a decision rather than a lapse.

  6. 6

    Revocation happens on the date, and is verified

    Then the whole thing is already the evidence an access review needs.

What access request is made of

Four parts. The second is what stops the estate accumulating.

Owner-based routing

To the person accountable for the system, from a register that is maintained. A shared IT queue approves things nobody understands.

Expiry by default

Every grant ends unless somebody argues otherwise. Permanent access is a decision, not a default.

Real provisioning

Granted and revoked through the integration, so the record and the system agree without anybody reconciling them.

Review as a by-product

Who has what, granted by whom, why, and when it ends, produced continuously instead of assembled before an audit.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Begin by building the system owner register

    Routing is only as good as knowing who owns what.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Slack, Okta, Jira,
    Workday, Vanta and Snowflake, or whatever we run in those seats.
    Before you plan anything, tell me which of them are already
    authenticated in the workspace, because I do not want a connector
    stubbed that I have not authenticated.
    
    The detail that matters most is Okta. I need groups, applications, how
    assignment works, and which of our systems federate versus having
    local accounts.
    
    Then build a system owner register as a table: system, owner, deputy,
    sensitivity tier, default grant duration, and whether provisioning is
    automated or manual. This table is the whole workflow. Without it,
    requests route to a shared queue and get approved by somebody who cannot
    judge them.
  2. 2

    Take requests where people already are

    A portal nobody bookmarked produces direct messages instead.

    Headless skills build-workflow

    Use build-workflow. Accept requests from chat with a short form, and from
    the service desk for people who prefer it.
    
    Ask for: the system, the access level, how long, and the business reason.
    
    The reason field is not bureaucracy. It is the only thing that makes an
    access review decision possible a year later, when nobody remembers the
    project. Require it, and reject one-word answers.
    
    Pre-fill everything else from the directory: requester, manager, team,
    location. Never ask somebody for information the system already holds.
  3. 3

    Route to the owner, and expire by default

    Two rules that between them prevent most access sprawl.

    Route to the system owner from the register, with the deputy taking over
    if the owner is away. Chase after a day, escalate after two, because a
    request sitting for three days is a person finding a workaround.
    
    Set an expiry on every grant by default, from the sensitivity tier:
    
      low        90 days
      medium     60 days
      high       30 days
      privileged 7 days, and a second approver
    
    Permanent access requires an explicit reason and two approvers. It should
    be possible and it should be rare, and the difference between those two
    is entirely down to whether it is the default.
  4. 4

    Provision for real, and revoke on the date

    A ticket saying access was removed is not evidence that it was.

    Headless skills tray-gotchas

    Use tray-gotchas, then provision through the integration instead of by
    raising a task for somebody.
    
    Where a system cannot be automated, raise a tracked task with a deadline
    and verify completion by querying the system, not by somebody ticking a
    box.
    
    Warn the holder five days before expiry with one click to extend, and
    require a reason for the extension.
    
    On the expiry date, revoke and verify. Query the access back and confirm
    it is gone. A revoke call returning success and the access actually being
    gone are different facts, and the gap between them is what an audit
    finds.
  5. 5

    Produce the review as you go

    So the access review is a query rather than a quarter of somebody life.

    Record for every grant: who, what system, what level, approved by whom,
    the business reason, when it was granted, when it expires, and when it
    was revoked.
    
    Then produce these continuously, not before an audit:
    
      Everybody with a termination date who still holds access. This should
      be zero.
      Grants past their expiry that were not revoked.
      Permanent grants, with their reasons, ranked by sensitivity.
      Systems with no owner in the register, which is how requests end up
      in a shared queue.
      Approval turnaround by owner, because a slow owner produces
      workarounds, not patience.
  6. 6

    Prove it works, then hand the register to IT

    Because owners and durations change constantly.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production.
    
    Then open the same workflow in Tray Build so IT operations can maintain
    the owner register, the sensitivity tiers and the default durations in
    the visual canvas. Ownership changes with every reorganisation, and a
    stale register routes approvals to people who left.

What it connects to

Requests arrive in chat, approvals need an owner, and provisioning has to be real.

ServiceNow

Raise the access request against a catalogue item and close it when the grant lands, so the request and the grant share one record.

Reads and writes

Slack

Take the request where people already are, route it to the owner, and warn holders before expiry.

Reads and writes

Okta

Resolve requesters, managers and owners, then grant and revoke group and application access for real.

Reads and writes

Jira

Raise a tracked task for systems that cannot be automated, with a deadline and a verification step.

Writes

Workday

Read leavers, so the report of people who left still holding access is based on the HR record instead of the directory.

Reads

Vanta

Feed the access evidence in, so the review is recorded where audits get answered from.

Writes

Snowflake

Land every grant and revocation, so access history over a year is a query instead of an export.

Writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Google BigQuery, Microsoft Teams, Azure Active Directory, SAP SuccessFactors, Jira Service Desk or Databricks.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This grants and removes access to production systems. It is the control an auditor tests first.

It lives on the platform, not in a terminal window

Scheduled expiry and revocation fire on the date whether or not anybody is watching, with retries and a record per grant.

Every grant is evidence

Who, what, why, approved by whom, and when it ended. That set answers an access review without anybody assembling it.

Credentials live in the workspace, never in the repo

This workflow holds the ability to grant access across the estate. Those credentials live in your workspace, scoped per system and separately revocable.

IT owns the register

System owners, sensitivity tiers and default durations open in Tray Build. A stale register is the failure mode, and it belongs to the team that knows.

Revocation is verified, not assumed

Query the access back after revoking. A success response and the access being gone are different facts.

Questions people ask

Why expire every grant by default?

Because a grant with no end date is permanent, and the access review that finds it a year later is doing work the request should have prevented. Permanent should be possible and rare.

Why route to the system owner?

Because only the owner can judge whether the access is reasonable. A shared IT queue approves requests nobody in it understands, which is approval in name only.

Why require a business reason?

Because it is the only thing that makes a review decision possible a year later. Without it, a reviewer looking at a grant from a finished project has no basis to remove it and leaves it in place.

Is a ticket saying access was removed enough?

No. Query the system and confirm. A revoke call returning success and the access actually being gone are different facts, and an auditor tests the second one.

What report matters most?

People with a termination date who still hold access. It should read zero, and until somebody produces it continuously it never does.

Vibe-coding app guides

Vibe-code an entire app with Helix

This moves the data between systems. It does not give anybody a screen to work in. Build that app in Claude Code, Codex or Cursor, then deploy and run it governed on Tray Helix. Same kind of guide, same kind of prompts.

How to build an access request and approval app (opens helix.tray.ai in a new tab)

Last reviewed September 2026.