# How we handle access requests

An access request in Slack triggers an agent to check policy, gather context, and prepare a least-privilege grant, with every grant requiring a human approval and logged.

Canonical page: https://kortix.com/use-cases/access-requests

Access requests arrive constantly and informally. Someone needs a repo, a role in
Okta, or a cloud IAM permission to finish a task, and they ask in Slack. Whoever
holds the access has to check what the person's role should have, work out the
narrowest grant that unblocks them, apply it, and remember to record it. Under
time pressure the easy path is to grant broadly and move on, and the record of
who has what drifts.

We handle this by tying the grant to the request that starts it, and to the
policy that governs it. This writes up how we run that on Kortix — the
connections, the steps, and the guardrails — so you can set up the same flow.

- **Team:** Kortix
- **Trigger:** An access request in Slack
- **Connected systems:** Okta · GitHub · Cloud IAM
- **Mode:** Policy-checked · Approval-gated · Logged

## The problem

The common approaches each fall short. A ticket queue routes the request to a
person who still does all the lookup and grant work by hand. A standing broad
role avoids the back-and-forth but hands out more than the task needs. And a
self-serve grant with no policy check trades safety for speed. None of them keep
a clean record of what was granted and why.

We wanted each request checked against policy, scoped to the least privilege that
unblocks the work, and granted only after a person signs off, with a log left
behind.

## What we built

On Kortix, an access request in Slack triggers an agent. Each request runs in its
own isolated session — a cloud sandbox — with scoped access to Okta, GitHub, and
cloud IAM. The agent reads the request, checks it against policy, gathers context
on the person's role, team, and the least-privilege scope that fits, and prepares
the grant. Every grant requires a human approval, and each one is logged.

## How it works

### Connect Slack as the trigger

Slack is connected as a **channel**, so a request is the trigger. Post the access
request and it spawns a fresh **session** in its own sandbox, seeded with who's
asking and what they need. One request, one session, one disposable machine.

### Give the agent the access policy

Which roles map to which grants, what least privilege means for each system, and
which requests need extra scrutiny are stored as **skills** and **memory** that
load into every session. The agent checks requests against that policy rather
than improvising, and it updates as the policy changes.

### Connect what a grant can touch

Through scoped **connectors**, brokered server-side so no raw token reaches the
model, the agent can:

- **Read Okta** — the requester's role, team, and current group memberships.
- **Prepare a GitHub grant** — repo or team access scoped to what the task needs.
- **Prepare a cloud IAM grant** — the narrowest role or permission set that
unblocks the work.

### Set the guardrails

Granting access is the step that changes who can do what, so every grant stops at
a **human approval gate** — no access is applied until a person signs off. Each
approved grant is logged with the request, the policy check, and the scope.
Credentials are encrypted in the secrets manager and injected at runtime, scoped to the agents you grant them to.

### Let each request come back scoped and logged

With that in place, a request in Slack comes back as a policy-checked,
least-privilege grant ready for a person to approve, with a record attached. "I
need access to this repo" becomes a scoped GitHub grant; "I need this cloud role"
becomes the narrowest IAM permission that fits, both held for sign-off.

> **The pattern**
> Connect Slack via a **channel** trigger, give the agent scoped **connectors**
> into Okta, GitHub, and cloud IAM, encode the access policy as **skills** and
> **memory**, and gate every grant behind a human with a log left behind.

## Guardrails

Giving an agent a hand in access decisions is a trust question. The relevant
controls on Kortix:

- **Isolation.** Every request runs in its own isolated sandbox on its own branch.
  The session is granted access only to the systems it's scoped to, and only what it's
  explicitly allowed to send is written back out.
- **Scoped secrets.** Each credential is encrypted in the secrets manager,
  injected into the sandbox at runtime, and scoped to the agents you grant them to or the
  logs.
- **Human approval gate.** No grant is applied until a person approves it, and
  each approved grant is logged.
- **Everything is code.** The agent's persona, skills, and permissions are files
  in the repo — versioned and changed through a reviewed **change request**, not
  a dashboard setting.

## The outcome

- **Least privilege:** Every grant scoped to what the task needs
- **Approval-gated:** No access applied without a person signing off
- **Logged:** Every grant recorded with its request and scope

Access requests that used to be granted broadly under time pressure now come back
scoped, policy-checked, and ready for a person to approve, with a record left
behind. Extending it to another system means connecting one more platform.
