---
title: "Just-in-time access"
---

# Just-in-time access

Give people eligible roles they activate when needed, require approval, use break-glass for emergencies, and let people request access to a single resource in Neural Inverse Govern.

Just-in-time (JIT) access replaces standing privilege with access that a person switches on for a limited time, with a reason, a fresh second factor and, where you require it, someone else's approval. The console page is **Access > JIT and break-glass**.

## Make a role eligible

Create a binding with `state: "eligible"` instead of `active`. Eligible bindings are held by users (an activation on a group binding would unlock the role for every member).

```bash
curl -sS -X POST "$KEYSTONE_URL/api/v1/access/bindings" \
  -H "Authorization: Bearer $ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"node_id": "'$PROJECT_NODE'", "principal_type": "user", "principal_id": "'$USER_ID'",
       "role_id": "'$ROLE_ID'", "state": "eligible", "requires_approval": true,
       "max_activation_minutes": 120, "description": "Production deploys"}'
```

| Field | Meaning |
|---|---|
| `requires_approval` | The activation waits for an approver |
| `max_activation_minutes` | 1 to 10080, bounded by the organisation's `jit_max_minutes` |
| `break_glass` | Marks an emergency binding (below) |

The escalation guard applies as for any binding; see [Roles and permissions](https://neuralinverse.com/docs/govern/roles/#the-escalation-guard).

## Activate

The person sees what they can activate with `GET /api/v1/access/me/eligibility`, and activates with:

```bash
curl -sS -X POST "$KEYSTONE_URL/api/v1/access/activations" \
  -H "Authorization: Bearer $USER_TOKEN" -H 'Content-Type: application/json' \
  -d '{"binding_id": "'$BINDING_ID'", "justification": "Hotfix for incident 2026-114",
       "minutes": 60, "mfa_code": "123456"}'
```

- `justification` is 10 to 2000 characters.
- `mfa_code` is a fresh TOTP code.
- The person needs `iam.activations:request` on the binding's node. Every resource role holds it.
- The answer is `active`, or `pending_approval` when the binding requires approval.

Activations end on their own at the end of their duration. The holder, or someone with `iam.activations:approve` on the node, can end one early with `POST /api/v1/access/activations/{id}/end`.

## Approve

A pending activation appears in the approvals inbox with source `access_activation`. Only someone who holds `iam.activations:approve` on the node and is not the requester can approve it. Pending activations are settled every 30 seconds from the approval decision. The organisation's `approval_timeout_minutes` setting bounds how long approval is awaited. See [Approvals](https://neuralinverse.com/docs/govern/approvals/).

## Break-glass

A binding with `break_glass: true` is eligible only. Activating it:

- skips approval, but still needs a justification and a fresh second factor;
- is capped by the organisation's `break_glass_max_minutes`;
- raises an alert: an audit record marked for alerting and the organisation webhook event `access.breakglass.activated`;
- opens a mandatory post-use review that someone other than the user completes.

The review is `POST /api/v1/access/activations/{id}/review` with `{"outcome": "appropriate" | "inappropriate", "notes": "..."}` after the activation has ended. It needs `iam.breakglass:review` on the node. Reading break-glass activations of others needs `iam.breakglass:read`.

Break-glass for signing in while SSO is required is a different feature; see [Domains and SSO enforcement](https://neuralinverse.com/docs/govern/sso-enforcement/#break-glass).

## Temporary authority stays temporary

Authority that comes from an activation can create only bindings that expire no later than the activation, cannot share resources, revoke shares or decide resource access requests, and never counts for Owner-reserved actions. An activation cannot be turned into standing access.

## Activation routes

| Route | Who |
|---|---|
| `GET /api/v1/access/activations` | Own activations; anyone's with `iam.activations:read` (and `iam.breakglass:read` for break-glass) on the organisation node |
| `POST /api/v1/access/activations` | The holder of the eligible binding |
| `GET /api/v1/access/activations/{id}` | Own, or `iam.activations:read` on the node |
| `POST /api/v1/access/activations/{id}/end` | The holder, or `iam.activations:approve` on the node |
| `POST /api/v1/access/activations/{id}/review` | `iam.breakglass:review` on the node, not the person who activated |
| `GET /api/v1/access/me/eligibility` | Signed in, own only |

## Resource access requests

A person who lacks access to one object (a project, a model connection, an MCP server and the other shareable types) can ask for a level on it:

| Route | Who |
|---|---|
| `POST /api/v1/access/resources/{type}/{id}/requests` | Anyone signed in: ask for a level with a reason; one open request per person and object |
| `GET /api/v1/access/resources/{type}/{id}/requests` | Managers of the object |
| `POST /api/v1/access/resource-requests/{id}/approve`, `/deny` | A Manager of the object who is not the requester (`403 self_approval` otherwise) |
| `POST /api/v1/access/resource-requests/{id}/withdraw` | The requester |
| `GET /api/v1/access/me/resource-requests` | The caller's own requests |

Approval grants the level in the same transaction. Requests and decisions are audited (`access.request.approved` or `denied`) and send the webhook event `access.request.created`. A request for an object that does not exist is filed like any other and denied by the scheduler, so requests cannot be used to probe for objects.

Self-service requests for IDE and tool access (`/api/v1/me/access-requests`) are a separate, partial feature: an approval is recorded but grants nothing on the device yet.

## Compliance overrides

**Access > Compliance overrides** lists compliance break-glass overrides (`/api/v1/compliance/break-glass`, `compliance:read` to read and `compliance:manage` to create or remove).
