---
title: "Usage"
manual: "API_KEY"
version: "1.1"
permalink: "https://docs.typo3.org/permalink/maikschneider/api-key:usage@1.1"
source: "Usage/Index.rst"
rendered: "2026-10-29T10:57:23+00:00"
---

# Usage {#usage}

## Key format {#usage-key-format}

A key consists of the prefix `t3key_` and 32 random bytes in unpadded
base64url, 49 characters in total:

```text
t3key_KhhNfTRL-5tLoriJVo5I-BQRJWiLD3GqlvEcPDPeHmg
```

The prefix plus the next eight characters (`t3key_KhhNfTRL`) form the
*identifier*. It is stored in plain text, shown in the backend and in logs,
and identifies a key without revealing it. The full key is only shown once,
when it is created. The database stores an HMAC hash of it.

## Sending a key {#usage-requests}

Send the key in one of two headers:

```bash
curl -H 'X-API-Key: t3key_KhhNfTRL-5tLoriJVo5I-BQRJWiLD3GqlvEcPDPeHmg' \
    https://example.com/api/articles

curl -H 'Authorization: Bearer t3key_KhhNfTRL-5tLoriJVo5I-BQRJWiLD3GqlvEcPDPeHmg' \
    https://example.com/api/articles
```

Prefer `X-API-Key` behind Apache, see [Apache and the Authorization header](https://docs.typo3.org/permalink/maikschneider/api-key:security-apache@1.1). Never put a
key in the query string; such requests are always rejected.

In CI pipelines and scripts read the key from a secret variable instead of
writing it into the script:

```bash
curl --fail -H "X-API-Key: ${TYPO3_API_KEY}" https://example.com/api/articles
```

## Managing keys on the command line {#usage-cli}

### Create a key {#usage-cli-create}

```bash
vendor/bin/typo3 apikey:create --title="CI deploy"
```

-   **--title**

    -   *Type:* string
    -   *Required:* true

    A label that tells you what the key is used for.

-   **--fe-user**

    -   *Type:* int

    Binds the key to a frontend user. Without `--fe-user` and `--be-user`
    the key is a service key.

-   **--be-user**

    -   *Type:* int

    Binds the key to a backend user. A key is bound to one user at most.
    A bound user that is deleted, disabled or outside its start and end time
    makes the key invalid.

-   **--created-by**

    -   *Type:* int

    Records a backend user as creator of the key, e.g. the person who
    requested it. The creator is shown in the backend and by
    `apikey:list`, and does not affect authentication.

-   **--scope**

    -   *Type:* string, repeatable

    Restricts the key to a scope. The extension does not interpret scopes; the
    API that consumes the key defines them, e.g. `articles:read`. Commas
    separate several scopes in one value. A key without scopes is
    unrestricted, but a given `--scope` without a value (`--scope=","`) is
    rejected. The same applies to `--allowed-ip` and `--site`.

-   **--expires**

    -   *Type:* string

    A date (`2027-01-01`) or a relative time (`+90 days`) after which the
    key stops working.

-   **--allowed-ip**

    -   *Type:* string, repeatable

    Restricts the key to an IP address or a CIDR range, e.g. `10.0.0.0/8`
    or `2001:db8::/32`.

-   **--site**

    -   *Type:* string, repeatable

    Restricts the key to the site with this identifier.

The command prints the key once. Store it in your secret manager right away;
it cannot be recovered.

### List keys {#usage-cli-list}

```bash
vendor/bin/typo3 apikey:list
```

Shows identifier, title, bound user, scopes, expiry, last use and status of
every key. Secrets are never shown.

### Revoke a key {#usage-cli-revoke}

```bash
vendor/bin/typo3 apikey:revoke t3key_KhhNfTRL
vendor/bin/typo3 apikey:revoke 12
```

Takes the identifier or the uid. Revoking hides the record, so it stays
available for auditing.

## Managing keys in the backend {#usage-backend-module}

Administrators create and edit keys in the regular record form, like any
other record on the root page (**Content > Records**, page 0).
The key is generated when the record is saved. The form then shows it once,
with a button that copies it to the clipboard. Only its hash is stored, so
reloading the form or opening it again does not show it any more.

**Bound to** selects whether the key is a service key or bound to a
frontend or backend user, and shows only the matching user field. Switching
it clears the binding of the other user type when the record is saved.

The same rules apply as for [apikey:create](https://docs.typo3.org/permalink/maikschneider/api-key:usage-cli-create@1.1). A
record that breaks one, for example an invalid IP range or a key bound to a
frontend and a backend user at once, is not saved, and the error is shown
above the form.

On TYPO3 v14 the module **Administration > Integrations > API
Keys** lists all keys with their identifier, identity, scopes, expiry, last
use and status. **Create API key** and the edit button open the
record form. The revoke button hides the record, like
[apikey:revoke](https://docs.typo3.org/permalink/maikschneider/api-key:usage-cli-revoke@1.1). A key that was saved with
**Save and close** is shown once at the top of the module instead.

Until the key is shown, it is kept in the backend user session, encrypted
with a key derived from the session id. The session table only stores a hash
of that id, so the database alone does not reveal it.

## Secret scanning {#usage-secret-scanning}

The fixed prefix lets secret scanners find keys that end up in a repository.

[GitHub custom pattern](https://docs.github.com/en/code-security/secret-scanning/using-advanced-secret-scanning-and-push-protection-features/custom-patterns/defining-custom-patterns-for-secret-scanning):

```text
t3key_[A-Za-z0-9_-]{43}
```

[gitleaks](https://github.com/gitleaks/gitleaks) rule:

```toml
[[rules]]
id = "typo3-api-key"
description = "TYPO3 API key (maikschneider/api-key)"
regex = '''t3key_[A-Za-z0-9_-]{43}'''
keywords = ["t3key_"]
```
