---
title: "Temporary access"
description: "Grant access that ends on its own: expiring access rules and group memberships, requestable groups decided by approvers, and revoking a grant early."
---

Access that ends on its own: a rule with an expiry, a group membership
with an expiry, and a request flow in which a user asks to join a group
for a while and an approver decides. Together they cover the on-call
window, the contractor's week and the "let me into prod for an hour"
without anyone having to remember to take the access away again.

## Expiring rules

An [access rule](/slopscale/ref/access-control#access-rules) takes an optional
`expiresAt`. Past it the rule stops applying; it stays in the list,
marked expired, until someone extends or deletes it, so the record of
what was open is kept. A new expiry must be in the future; an expired
rule may still be edited as long as its expiry is kept, extended or
cleared.

```console
slopscale access-rules create --name "Migration window" \
  --src 2 --dst 3 --protocol tcp --ports 5432 --expires 48h
slopscale access-rules update -i 7 --name "Migration window" \
  --src 2 --dst 3 --protocol tcp --ports 5432 --expires 2026-09-30T18:00:00Z
```

The console's rule editor has an _Expires_ field, and the rule list says
when a rule expires or that it did.

## Expiring memberships

A machine or user can be added to a group until a time. The membership
counts until then and is deleted afterwards; the rest of the group is
untouched. Adding the same member again for good makes the membership
permanent; a group edit that keeps the member keeps its expiry.

```console
slopscale groups add-node -i 4 --node 12 --expires 4h
slopscale groups add-user -i 4 --user 3 --expires 2026-09-12T09:00:00Z
```

The console's _Groups_ dialog on a machine or user has an _Until_ field
for the groups being joined, and `GET /api/v1/group/{id}` lists the
temporary memberships under `expiries`.

## Access requests

A group marked requestable takes requests from users. A signed-in user
asks to join it for a duration, between five minutes and thirty days,
for one of their machines or for every machine they own, with a reason.
An approver, anyone with the `policy_file` scope, approves the request
for the duration asked or another one, or denies it, with a note the
requester sees. Approval adds the membership with its expiry and
rebuilds the policy at once; nobody decides their own request. A pending
request can be withdrawn by its requester; a decided one stays on record
until an approver deletes it.

Requests need a user behind the credential: a console session, or an
API key owned by a user. A member holds no admin scope and can still
file and follow their own requests. The console shows them under
_My access_, which every signed-in user has, and shows an approver the
queue on the _Requests_ page under _Access controls_, with the number
pending next to it in the sidebar.

```console
slopscale groups create --name "Prod" --requestable
slopscale access-requests create --group 4 --node 12 --duration 2h --reason "deploy"
slopscale access-requests list --status pending
slopscale access-requests approve -i 1 --duration 1h --note "one hour is enough"
slopscale access-requests deny -i 2 --note "ask the team lead first"
slopscale access-requests revoke -i 1 --note "incident over"
slopscale access-requests cancel -i 3
```

Through the API, `GET /api/v1/access-request/options` lists what the
caller may ask for, `POST /api/v1/access-request` files a request,
`GET /api/v1/access-request` lists them (every one for
`policy_file:read`, otherwise the caller's own; `?mine=true` and
`?status=pending` narrow), `POST /api/v1/access-request/{id}/approve`
and `/deny` decide, `POST /api/v1/access-request/{id}/revoke` ends a
grant early, and `DELETE /api/v1/access-request/{id}` withdraws or
deletes.

## Ending a grant early

An approver does not have to wait for a grant to run out. Revoking it
drops the membership the approval added, rebuilds the policy at once and
marks the request revoked with who ended it, when and why; the approval's
own record stays, so the request still says who granted it. Only access
that is in effect can be revoked, and an approver may revoke their own.
Deleting a request whose access is in effect is refused: the row is what
shows the membership, so revoke it first.

The membership only goes when the approval is what put it there. A
member who was already in the group for good, or whose membership a
later approval extended further, keeps what it had: revoking one request
never takes away access another grant or an operator gave.

One member can hold several approvals for the same group at once, and
they share a single membership that ends with the last of them. Revoking
one of those does not empty the group: the membership falls back to the
furthest approval still standing, and goes only when none is left. So
revoking a long grant leaves a shorter one that has not run out alone,
and the member keeps the group until that one ends.

Removing the membership by hand says the same thing on the request.
Taking a machine or user out of the group, in the console, the CLI or
the API, marks revoked every approval that was keeping it there, so the
request list and the group never disagree. That path is a membership
change rather than a decision, so it raises no `accessRequestRevoked`
event; the requester learns of it the next time they look.

```console
slopscale access-requests revoke -i 1 --note "incident over"
```

In the console the row menu on a request in effect has _Revoke access_,
and the _In effect_ tab of the _Requests_ page lists every grant that is
running, with when each one ends.

## When access ends

The server checks every minute for rules and memberships whose time has
passed, deletes the memberships and rebuilds the policy without them and
without the expired rules, so a grant ends within a minute of its time
and the clients get a new map. A membership that ends is not a policy
change to a webhook subscriber; the approval was. Postures with a
schedule (see [Device trust](/slopscale/ref/device-trust#schedules)) are the other
way to open access by the clock, for a window that repeats every week.

## Events and audit

The webhook events `accessRequestCreated`, `accessRequestApproved`,
`accessRequestDenied` and `accessRequestRevoked` carry the requester, the
group, the machine, the duration, the reason, the note and, once
approved, the expiry, so a Slack channel can follow the queue. The audit
log records `access_request.create`, `access_request.approve`,
`access_request.deny`, `access_request.revoke` and
`access_request.cancel`, and the existing `group.member.add` and
`access_rule.*` actions carry the expiry.

An email endpoint sent to `approvers` reaches whoever may decide a
request without a recipient list to keep up to date; see
[Webhooks](/slopscale/ref/webhooks#notifications). Subscribing one to
`accessRequestCreated` is what stops a request waiting until an approver
happens to open the page, and the _Requests_ page offers to set it up in
a click while nothing does.
