# Revoke the token you send, before it expires

- Endpoint: `POST /v1/api-account/revoke-token`
- Production: `https://api.main-team.org/v1/api-account/revoke-token`
- Sandbox: `https://apisnd.main-team.org/v1/api-account/revoke-token`
- Operation: `revokeToken` (API account)
- Authentication: `Authorization: Bearer <token>`, a short-lived token you sign with your API key and secret
- Permission: `api/*:$org:$ID`

## Description

Revokes the bearer token this request carries. Send no body. From now on that token answers `401 unauthorized` everywhere, this operation included, so sending it again with the same token answers `401`. Only this token is revoked: your other tokens work until they expire.

`data.expiresIn` is how many seconds the revocation is held: what was left of the token’s life plus 30 seconds of clock tolerance, at least 1 and at most 3660. After that the token would be refused as expired anyway.

Use it when a token may have leaked, or when the session it served ends. It needs the `api/*` permission, which only a role whose action is `api/*`, `*/*` or `*` grants; a role for the student or exam operations does not. An account without it cannot revoke its tokens, so keep them short-lived.

## Response

`200` Success: `message` is "Token revoked successfully".

```json
{
  "success": true,
  "message": "Token revoked successfully",
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 57,
    "totalPages": 3
  },
  "data": {
    "expiresIn": 1830
  }
}
```

## Errors

| Status | Code | When |
| --- | --- | --- |
| 400 | [`bad_request`](https://hub.main-team.org/api/errors#bad_request) | The token could not be read back or has no `exp`. A token that passed authentication always can, so you should never see this; nothing was revoked. |
| 401 | [`unauthorized`](https://hub.main-team.org/api/errors#unauthorized) | The token is missing or malformed, is not signed with your account’s `apiSecret`, breaks the `iat` and `exp` rules, has expired or been revoked, or its account is not active. All of these answer the same. |
| 403 | [`forbidden`](https://hub.main-team.org/api/errors#forbidden) | The token is valid, but no role on your account allows `api/*` on `mto`, the organization every operation without `:organizationId` acts on, or a role denies it. |
| 429 | [`too_many_requests`](https://hub.main-team.org/api/errors#too_many_requests) | Your account has made more than 100 requests to this operation in the current 60-second window. Wait the seconds in `Retry-After` before sending again. |
| 500 | [`internal_error`](https://hub.main-team.org/api/errors#internal_error) | Something failed on our side. Retry later, and quote `request_id` if it goes on. |

## Code samples

### curl

```bash
# $TOKEN: a short-lived token you minted with your API key and secret
curl -sS -X POST 'https://api.main-team.org/v1/api-account/revoke-token' \
  -H "Authorization: Bearer $TOKEN"
```

### Node.js

```js
const token = process.env.TOKEN; // a short-lived token you minted with your API key and secret

const res = await fetch('https://api.main-team.org/v1/api-account/revoke-token', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
console.log(body.data);
```

### PHP

```php
<?php
$token = getenv('TOKEN'); // a short-lived token you minted with your API key and secret

$ch = curl_init('https://api.main-team.org/v1/api-account/revoke-token');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $token,
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$body = json_decode($response, true);
if ($status >= 400) {
    $error = $body['error'];
    throw new RuntimeException("$status {$error['code']}: {$error['message']}");
}
print_r($body['data']);
```
