---
title: Revoke a Grant | Keycard
description: Cut off an Application's access on behalf of a User by revoking a grant, from the Console or the management API.
---

A **grant** records that a User authorized an Application to reach a specific Resource on their behalf. When a User approves an Application on a [consent screen](/concepts/applications/#consent/index.md), Keycard stores a grant that captures the Resource, the [Provider](/concepts/providers/index.md) behind it, and the scopes approved. From then on, Keycard [issues credentials](/concepts/credentials/index.md) for that access without prompting the User again.

Revoking a grant withdraws that authorization. You’d do this when:

- **Offboarding** a person or decommissioning an Application.
- A **compromised or misbehaving agent** needs to be cut off.
- An Application ended up **over-scoped** and you want to force it back through consent.
- You’re **wrapping up a proof of concept** and want to clean up the access it accumulated.

Grant vs. policy vs. credential

These three controls are related but distinct:

- A [**policy**](/admin/access-policies/index.md) decides whether a User and Application are *allowed* to access a Resource. It’s a standing rule you author.
- A **grant** records that a User *authorized* a specific Application to act for them against a Resource. It’s the consent, captured per User.
- A [**credential**](/concepts/credentials/index.md) is the short-lived token Keycard issues once policy and consent both pass.

Revoking a grant removes the authorization. It doesn’t change your policies, and — as covered [below](#what-happens-after-you-revoke) — it doesn’t reach back and kill credentials that were already issued.

## Who can revoke grants

Grants live in your organization, and revoking one is a management operation, so it requires a management role:

- **Admins** (organization-wide) and **Managers** of a [custom Zone](/concepts/zones/index.md) can view and revoke grants for people in that scope.

**Viewers** are read-only: they can see grants but not revoke them.

[Roles & Permissions ](/admin/roles-and-permissions/index.md)Full RBAC reference for management operations

## Before you begin

- Sign in to the [Keycard Console](https://console.keycard.ai) with an Admin or Manager role.
- Know which **person** holds the grant. Grants are managed per User from the **People** page.
- People and grants live in your **organization** by default. If the access was granted in a [custom Zone](/concepts/zones/index.md), switch to that Zone from the **Zones** page first.
- For the management API, have your organization’s `<zone-id>` (its org Zone) and a service-account token.

## Revoke a grant

- [Console](#tab-panel-55)
- [HTTP](#tab-panel-56)
- [Python](#tab-panel-57)

1. **Open the person’s profile**

   In the left nav, go to **People** and click the person whose access you want to withdraw. Their profile shows their identifiers, last activity, and two tabs: **Sessions** and **Grants**.

2. **Open the Grants tab**

   Select **Grants**. Each row is one grant, showing the **Entity** (the Resource, such as `Google Calendar API`), its **Provider**, the approved **Scopes**, a **Status** (`Active now` or `Revoked`), and when it **Expires** (for example, `refreshable`). Active grants are listed first.

3. **Revoke the grant**

   On the grant’s row, open the actions menu (**⋯**) and choose **Revoke grant**.

   ![Grants tab on a person's profile with the actions menu open, showing View in audit log and Revoke grant](/images/light/grants/revoke-grant.png) ![Grants tab on a person's profile with the actions menu open, showing View in audit log and Revoke grant](/images/dark/grants/revoke-grant.png)

4. **Confirm the status flipped**

   The grant’s **Status** changes to **Revoked**. Use **Refresh** if the list doesn’t update immediately. See [Verify the revocation](#verify-the-revocation) to confirm the effect on live traffic.

All management API requests use a Bearer token obtained from your service account’s client credentials. If you haven’t set that up, follow the [Authenticate step in Access Policies](/admin/access-policies/#setup/index.md) — the same token works here. In the paths below, `<zone-id>` is your organization’s Zone (its org Zone), or a custom Zone’s ID if the grant lives there.

1. **List the grants in the Zone**

   Find the grant you want to revoke. Filter by the person’s user ID, and optionally `status=active`.

   ```
   curl "https://api.keycard.ai/zones/<zone-id>/delegated-grants?user_id=<user-id>&status=active" \
     -H "Authorization: Bearer $ACCESS_TOKEN"
   ```

   Each entry in `items` has an `id` — that’s the grant you’ll revoke.

2. **Revoke the grant**

   Set the grant’s status to `revoked`. This mirrors the Console’s **Revoke grant** action: the grant stays listed with **Status: Revoked**.

   ```
   curl -X PATCH https://api.keycard.ai/zones/<zone-id>/delegated-grants/<grant-id> \
     -H "Authorization: Bearer $ACCESS_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"status": "revoked"}'
   ```

   To permanently remove the grant instead of marking it revoked, send `DELETE` to the same path — it returns `204 No Content`.

All management API requests use a Bearer token obtained from your service account’s client credentials. See the [Authenticate step in Access Policies](/admin/access-policies/#setup/index.md) for the full token exchange. Here `zone_id` is your organization’s Zone (its org Zone), or a custom Zone’s ID if the grant lives there.

1. **List the grants in the Zone**

   ```
   grants = requests.get(
       f"{base}/zones/{zone_id}/delegated-grants",
       headers=headers,
       params={"user_id": user_id, "status": "active"},
   ).json()


   for grant in grants["items"]:
       print(grant["id"])
   ```

2. **Revoke the grant**

   Set the grant’s status to `revoked` — the same action as the Console’s **Revoke grant**:

   ```
   requests.patch(
       f"{base}/zones/{zone_id}/delegated-grants/{grant_id}",
       headers=headers,
       json={"status": "revoked"},
   )
   ```

   To permanently remove the grant instead, use `requests.delete(...)` on the same path.

No dedicated CLI command

The Keycard [CLI](/cli/index.md) doesn’t have a grant-revocation command today. If you script against the management API, you can reach the same endpoint through the generic passthrough, which authenticates against the Management API:

```
keycard agent api /zones/<zone-id>/delegated-grants/<grant-id> \
  -X PATCH -d '{"status": "revoked"}'
```

## What happens after you revoke

Revoking a grant stops Keycard from issuing **new** access for that User and Resource. It does **not** reach out and invalidate credentials that are already in the wild.

**New credential requests stop.** The next time the Application asks Keycard for a credential for that access — a fresh [token exchange](/concepts/credentials/#delegation-chaining/index.md) or a [refresh](/concepts/credentials/#refreshing/index.md) — Keycard has no grant to satisfy it and the request fails with `insufficient_authorization` (an `OAuth2Error`) and the message *User authorization is required for resource `<resource-url>`*. The User has to authorize the access again before anything is issued, so the Application should treat this as a re-authentication prompt.

**Already-issued credentials live until they expire.** Keycard issues short-lived credentials, but there is no per-token kill-switch today. A token the agent already holds keeps working against the Resource until it expires on its own. In practice, access stops within the lifetime of the current credential — not the instant you click **Revoke grant**.

**Refresh stops.** A grant that shows `refreshable` in the Console can mint new credentials without re-prompting the User. Revoking the grant ends that — refresh attempts fail, so the Application can’t quietly extend its access past the current token.

**Brokered credentials are a special case.** For [brokered access](/concepts/resources/#brokered-access/index.md) to an external Provider (Google, GitHub, and so on), revoking the Keycard grant stops Keycard from brokering *new* credentials — but it does not sign the User out at the Provider or revoke a token the Provider already issued. To fully cut off external access, also revoke Keycard’s access from the Provider’s own connected-apps settings.

**What the agent or Application sees.** The current token keeps working against the Resource until it expires; after that, the Application can no longer obtain a new credential. Its next token request to Keycard fails with `insufficient_authorization` — the User must re-authorize. That’s distinct from `access_denied`, which is what a [policy](/admin/access-policies/index.md) denial returns.

One grant at a time

Revoking a grant is per-Resource, and there’s no per-token kill-switch — you can’t revoke a single outstanding credential. To cut a person off from *everything* at once rather than grant by grant, [disable or remove the person](#cut-a-person-off-entirely) instead.

## Cut a person off entirely

When you’re offboarding someone or responding to a compromise, revoking grants one at a time is slower than you want. From the **People** page, open the person’s access drawer (the **⋯** on their row) and use the **Danger zone**:

- **Disable user** blocks the person from signing in or obtaining new credentials while keeping their account and configuration intact. It’s reversible.
- **Remove from organization** removes the person entirely.

You can’t disable or remove yourself.

![Person's access drawer showing Organization role, Zone access, and a Danger zone with Disable user and Remove from organization](/images/light/grants/disable-user.png) ![Person's access drawer showing Organization role, Zone access, and a Danger zone with Disable user and Remove from organization](/images/dark/grants/disable-user.png)

Disabling or removing a person stops new credential issuance the same way revoking a grant does; credentials their Applications already hold keep working until they expire.

## Verify the revocation

1. **Check the grant status.** On the person’s **Grants** tab, the revoked grant now shows **Status: Revoked**.

2. **Check the Audit Log.** From the grant’s actions menu, choose **View in audit log**, or open the [Audit Log](/admin/audit-log-export/index.md) directly. After revocation, the Application’s next attempt shows as a **Failure** on the credential exchange (resource path `/oauth/2/token`), with error code `insufficient_authorization` and the message *User authorization is required for resource `<resource-url>`*. The event’s actor is the full identity chain — the Application and the User it acted for.

   ![Audit Log entry showing a Failure on the credential exchange with error code insufficient\_authorization](/images/light/grants/audit-revoked.png) ![Audit Log entry showing a Failure on the credential exchange with error code insufficient\_authorization](/images/dark/grants/audit-revoked.png)

3. **Retry from the Application.** Once the current credential expires, trigger the Application again. Its next token request to Keycard should fail with `insufficient_authorization`, and the **Grants** tab should still show the grant as **Revoked**.

## Re-grant access

Revocation isn’t permanent. To restore access, the User goes back through the [authorization flow](/concepts/credentials/#user-delegation/index.md) and approves the [consent screen](/concepts/applications/#consent/index.md) again. Keycard records a new grant and credential issuance resumes.

For an Application configured with implicit consent, there’s no screen to approve — the grant is re-created automatically the next time the User runs the flow.

## Related

- [Access Policies](/admin/access-policies/index.md) — the standing rules that decide who’s allowed access in the first place
- [Credential Issuance](/concepts/credentials/index.md) — how Keycard issues, refreshes, and brokers the credentials a grant unlocks
- [Applications](/concepts/applications/#consent/index.md) — the consent model and how grants are created
- [Providers](/concepts/providers/index.md) — the external providers behind brokered grants
- [Audit Log Export](/admin/audit-log-export/index.md) — stream credential and access events to your SIEM
- [Roles & Permissions](/admin/roles-and-permissions/index.md) — who can perform management operations
