> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opentype.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# secret_in_path

> HTTP 400 on the key routes: a key secret was sent in the URL instead of the key id. Rotate that key now, then call again with its key_ id.

`secret_in_path` means a key route received an API key secret (`otsk_...`) where it expects a key id (`key_...`). Read this page right away if you see it: the secret has been written into a URL and must be treated as leaked.

| HTTP  | `code`           | Retryable                                |
| ----- | ---------------- | ---------------------------------------- |
| `400` | `secret_in_path` | No. Rotate the key, then use the key id. |

<Warning>
  Rotate the key named by that secret now. URLs end up in proxy logs, browser history, monitoring tools and error trackers, so the secret may already be stored outside your control.
</Warning>

## What happened

Routes:

* `GET /v1/keys/{key_id}`
* `DELETE /v1/keys/{key_id}`
* `POST /v1/keys/{key_id}/rotate`

The path value starts with `otsk_`, which is the prefix of a key secret. OpenType refused the request without acting on the key. Two values look alike but do different jobs:

| Value      | Looks like                                                          | Use                                             |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------- |
| Key id     | `key_` + 32 hex, for example `key_d92a9043204d41c09c78fc813d54ef06` | goes in URLs; it is not a credential            |
| Key secret | `otsk_` + 64 hex                                                    | goes only in the `Authorization: Bearer` header |

## How to fix

1. Find the key's id. Call `GET /v1/keys` and match the first 13 characters of the leaked secret against `secret_prefix`, or look the key up on the [API keys page](/console/api-keys).
2. Rotate it with `POST /v1/keys/{key_id}/rotate`. The response carries a new `secret`, shown once. The old secret stops working at once.
3. Put the new secret in your secret store and redeploy the services that use it.
4. If the key is no longer needed, revoke it with `DELETE /v1/keys/{key_id}` instead.
5. Fix the code that built the URL so it uses the key's `id`, never its `secret`.

## Example

```json theme={"system"}
{"error":{"code":"secret_in_path","message":"that value looks like a key secret, not a key id; rotate it and pass the key_ id","request_id":"req_7d3f0c1a9b2e4f6a8c0d1e2f3a4b5c6d"}}
```

Rotating the key by its id. The call needs `keys_write`.

<CodeGroup>
  ```bash curl theme={"system"}
  curl -X POST https://api.opentype.dev/v1/keys/key_d92a9043204d41c09c78fc813d54ef06/rotate \
    -H "Authorization: Bearer $OPENTYPE_API_KEY"
  ```

  ```typescript TypeScript theme={"system"}
  const keyId = "key_d92a9043204d41c09c78fc813d54ef06"; // the id, never the otsk_ secret

  const res = await fetch(`https://api.opentype.dev/v1/keys/${keyId}/rotate`, {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.OPENTYPE_API_KEY}` },
  });

  const body = await res.json();
  if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
  // body.secret is the new secret, returned only here. The old one no longer works.
  console.log(body.id, body.secret_prefix);
  ```

  ```python Python theme={"system"}
  import os
  import requests

  key_id = "key_d92a9043204d41c09c78fc813d54ef06"  # the id, never the otsk_ secret

  resp = requests.post(
      f"https://api.opentype.dev/v1/keys/{key_id}/rotate",
      headers={"Authorization": f"Bearer {os.environ['OPENTYPE_API_KEY']}"},
      timeout=30,
  )

  body = resp.json()
  if not resp.ok:
      raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
  # body["secret"] is the new secret, returned only here. The old one no longer works.
  print(body["id"], body["secret_prefix"])
  ```
</CodeGroup>

## Related

* [Key rotation](/guides/key-rotation) - rotate in place or overlap two keys.
* [API key security](/security/api-key-security) - where secrets belong and where they never should.
* [malformed\_key\_id](/problems/malformed_key_id) - the path value is neither a secret nor a key id.
* [Problem codes](/problems) - every code, its status, and whether a retry can help.
