# `PhoenixKit.API.Keys.Token`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.64.1/lib/phoenix_kit/api/keys/token.ex#L1)

The API key token format: `pk_<prefix>_<secret>`.

- `prefix` is 8 lowercase hex characters (4 random bytes). It is stored in the
  clear, is unique, and is how a key row is found.
- `secret` is 32 random bytes written as 43 base64url characters (no padding).
  It may contain `_`, so a token is split on its first two underscores only.
- Only `SHA-256(secret bytes)` is stored (`secret_hash`). The token itself is
  shown once, when the key is created.

The secret has 256 bits of entropy, so a fast hash is enough: there is nothing
to brute-force, unlike a human password.

# `generate`

```elixir
@spec generate() ::
  {prefix :: String.t(), token :: String.t(), secret_hash :: binary()}
```

Generates a new token.

Returns `{prefix, token, secret_hash}`. Store `prefix` and `secret_hash`; show
`token` to the person once and forget it.

# `hash`

```elixir
@spec hash(binary()) :: binary()
```

SHA-256 of the raw secret bytes.

# `matches?`

```elixir
@spec matches?(binary(), binary()) :: boolean()
```

Constant-time comparison of two hashes.

# `parse`

```elixir
@spec parse(term()) :: {:ok, prefix :: String.t(), secret_hash :: binary()} | :error
```

Splits a presented token into its prefix and the hash of its secret.

Returns `:error` for anything that is not a canonical token: wrong length,
another scheme, upper-case prefix, a secret that is not exactly 32 bytes.

# `prefix`

```elixir
@spec prefix(term()) :: String.t() | nil
```

The prefix of a token, or `nil` when the text does not start like one.

Looks only at `pk_<8 hex>_`; it does not validate the secret. Safe for logging,
because the prefix is not secret.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
