Revoke an API key
Ory Talos Secure API Keys on Ory Network is in preview. The HTTP API is versioned v2alpha1, and request and response shapes can
change. Pin the version of the Ory SDK that you use.
Revoke an API key in Ory Talos Secure API Keys to stop it from working, for example when the secret leaked or its owner left.
Before you begin
- To manage keys in the Ory Console, you need the Owner or Developer role in the project. Members with the Viewer role can't view keys or send requests from the Playground.
- If an API key page in the Ory Console shows Enable Ory Talos, select Enable API keys. The change takes a short time to apply. See Eventual consistency.
To call the API, you need your project slug and a project API key.
A project API key is required for all administrative operations. To create one, read Creating API Keys.
The quickstart shows where to find the project slug and how to set up the TypeScript and Go SDKs. The examples on this page read both values from environment variables:
export PROJECT_SLUG=<your-project-slug>
export ORY_API_KEY=<your-project-api-key>
Revoke a key
Revocation permanently disables a key and can't be undone. The key stays in the list with the status Revoked, and its detail page shows the Revocation reason.
- Ory Console
- curl
- Go to API Keys → Keys in the Ory Console, open the row menu of the key, and select Revoke. On the key detail page, Revoke key is in the Danger zone section.
- In the Revoke API key? dialog, choose a Reason.
- If you choose Privilege withdrawn, you can explain the decision in Additional details.
- Select Revoke key.

Send POST /v2alpha1/admin/issuedApiKeys/{key_id}:revoke with an optional reason. If you leave out reason, the API records
REVOCATION_REASON_UNSPECIFIED. The optional description, up to 500 characters, is accepted only with
REVOCATION_REASON_PRIVILEGE_WITHDRAWN. With any other reason, a request that includes description fails with HTTP 400.
curl -sS -X POST "https://$PROJECT_SLUG.projects.oryapis.com/v2alpha1/admin/issuedApiKeys/${KEY_ID}:revoke" \
-H "Authorization: Bearer $ORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "REVOCATION_REASON_PRIVILEGE_WITHDRAWN", "description": "Contract ended"}'
A successful request returns HTTP 204 with an empty body. Revoking a key that is already revoked returns HTTP 409. For imported
keys, send the same request to POST /v2alpha1/admin/importedApiKeys/{key_id}:revoke.
| Reason in the Ory Console | API value | Use it when |
|---|---|---|
| No specific reason | REVOCATION_REASON_UNSPECIFIED | You don't record a reason. This is the default. |
| Key compromise | REVOCATION_REASON_KEY_COMPROMISE | The secret leaked, or someone else might have it. |
| Affiliation changed | REVOCATION_REASON_AFFILIATION_CHANGED | The owner's relationship with you changed, for example they left your team. |
| Superseded | REVOCATION_REASON_SUPERSEDED | A new key replaces this one. |
| Privilege withdrawn | REVOCATION_REASON_PRIVILEGE_WITHDRAWN | You withdrew the owner's permission to use the key. |
After you revoke a key:
- Verification of the key returns
is_valid: falsewith the error codeVERIFICATION_ERROR_REVOKED. - You can't derive new tokens from the key. Tokens that you derived before the revocation stay valid until they expire.
- The key no longer counts toward the active key limit.
Key holders can also revoke their own key without a project API key, by proving that they have the secret. This works for issued
and imported secret keys, not for public keys. They call POST /v2alpha1/apiKeys:selfRevoke (revokeApiKey in the SDK) with the
full secret in credential and an optional reason. The reason REVOCATION_REASON_PRIVILEGE_WITHDRAWN is for admins only and
returns HTTP 400. A successful request returns HTTP 200, also when the key is already revoked.
Revoke all keys of an actor
When a user leaves your organization or a customer closes their account, revoke all of their keys.
- Ory Console
- curl
- TypeScript
- Go
- On API Keys → Keys in the Ory Console, filter the list by the actor ID, and select Active in the Filters list.
- For each key in the list, revoke the key with the reason Affiliation changed.
This example lists the active issued keys of one actor and revokes each of them with the reason
REVOCATION_REASON_AFFILIATION_CHANGED:
BASE_URL="https://$PROJECT_SLUG.projects.oryapis.com"
curl -sS -G "$BASE_URL/v2alpha1/admin/issuedApiKeys" \
-H "Authorization: Bearer $ORY_API_KEY" \
--data-urlencode 'filter=actor_id="user:alice" AND status=KEY_STATUS_ACTIVE' \
--data-urlencode "page_size=1000" |
jq -r '.issued_api_keys[]?.key_id' |
while read -r KEY_ID; do
curl -sS -X POST "$BASE_URL/v2alpha1/admin/issuedApiKeys/${KEY_ID}:revoke" \
-H "Authorization: Bearer $ORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "REVOCATION_REASON_AFFILIATION_CHANGED"}'
done
Each run handles up to 1,000 keys. Revoked keys no longer match the filter, so run the script again until the list is empty.
This example lists the active issued keys of one actor and revokes each of them with the reason
REVOCATION_REASON_AFFILIATION_CHANGED:
import { ApiKeysApi, Configuration, RevocationReason } from "@ory/client"
const apiKeys = new ApiKeysApi(
new Configuration({
basePath: `https://${process.env.PROJECT_SLUG}.projects.oryapis.com`,
accessToken: process.env.ORY_API_KEY,
}),
)
const filter = 'actor_id="user:alice" AND status=KEY_STATUS_ACTIVE'
const keyIds: string[] = []
let pageToken: string | undefined
do {
const { data } = await apiKeys.adminListIssuedApiKeys({ filter, pageSize: 1000, pageToken })
for (const key of data.issued_api_keys ?? []) {
if (key.key_id) {
keyIds.push(key.key_id)
}
}
pageToken = data.next_page_token || undefined
} while (pageToken)
for (const keyId of keyIds) {
await apiKeys.adminRevokeIssuedApiKey({
keyId,
adminRevokeIssuedApiKeyBody: { reason: RevocationReason.RevocationReasonAffiliationChanged },
})
}
console.log(`Revoked ${keyIds.length} keys`)
This example lists the active issued keys of one actor and revokes each of them with the reason
REVOCATION_REASON_AFFILIATION_CHANGED:
package main
import (
"context"
"fmt"
"os"
ory "github.com/ory/client-go"
)
func main() {
cfg := ory.NewConfiguration()
cfg.Servers = ory.ServerConfigurations{{URL: "https://" + os.Getenv("PROJECT_SLUG") + ".projects.oryapis.com"}}
client := ory.NewAPIClient(cfg)
ctx := context.WithValue(context.Background(), ory.ContextAccessToken, os.Getenv("ORY_API_KEY"))
filter := `actor_id="user:alice" AND status=KEY_STATUS_ACTIVE`
var keyIDs []string
pageToken := ""
for {
req := client.ApiKeysAPI.AdminListIssuedApiKeys(ctx).Filter(filter).PageSize(1000)
if pageToken != "" {
req = req.PageToken(pageToken)
}
page, _, err := req.Execute()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
for _, key := range page.GetIssuedApiKeys() {
keyIDs = append(keyIDs, key.GetKeyId())
}
pageToken = page.GetNextPageToken()
if pageToken == "" {
break
}
}
reason := ory.REVOCATIONREASON_REVOCATION_REASON_AFFILIATION_CHANGED
for _, keyID := range keyIDs {
_, err := client.ApiKeysAPI.AdminRevokeIssuedApiKey(ctx, keyID).
AdminRevokeIssuedApiKeyBody(ory.AdminRevokeIssuedApiKeyBody{Reason: &reason}).
Execute()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
fmt.Printf("Revoked %d keys\n", len(keyIDs))
}
To revoke the imported keys of an actor with the API, use adminListImportedApiKeys and adminRevokeImportedApiKey. The list
response holds the keys in imported_api_keys, and the revoke request body is adminRevokeImportedApiKeyBody.