## TL;DR
Move the API key out of the query string and into the Authorization header, then rotate the key because the old one is already in your logs. Query params get logged everywhere: access logs, proxies, APM tools, error trackers. The fix is three parts: header-only transport, key rotation, and a lint rule so generated code never puts secrets in query params again.

## The query

```text
generated client sends the API key as a query param - the docs said header-only and the key leaked into logs
```

## Use this when

- The generated client builds URLs like `/v1/things` with the key appended as a query parameter
- The provider's docs say to send the key in a header
- You can find the key value in log aggregators or request logs
- The agent read a docs example that showed the key in the query string

## Not for

- OAuth access tokens leaking (different flow, different fix)
- Webhook signing secrets failing verification
- API keys committed to a git repo (rotate plus history rewrite, different playbook)
- Keys leaking through error messages or stack traces

## Steps

### 1. Confirm where the key is exposed

Search your logs for the key's prefix or a known fragment: the access log, the APM request traces, the error tracker. Write down every system that captured the full URL.

Expected output: a list of log systems that contain the key in query strings.

### 2. Rewrite the client to send the key as a header

Change the generated client to put the key in the Authorization header (or the provider's named header) and never in the URL. Strip any code that appends the key to query params.

```python
headers = {"Authorization": f"Bearer {api_key}"} # provider-specific scheme
resp = requests.get("https://YOUR-provider-domain/v1/things", headers=headers)
```

Expected output: requests succeed with no key material in the URL.

### 3. Rotate the key

The old key is compromised the moment it hit a log. Generate a new key in the provider's dashboard, deploy it, then revoke the old one. Do this even if the logs are "internal."

Expected output: old key revoked, new key live, zero downtime if you deploy-then-revoke.

### 4. Scrub or expire the exposed logs

For each system in step 1's list: delete the affected log entries, redact the key, or confirm the retention window has passed. At minimum, verify the old key no longer works so any retained copy is useless.

Expected output: no working key retrievable from any log system.

### 5. Add a guard to the scaffolder

Give the agent a rule: generated code must never interpolate a secret into a URL or query string. Add a post-generation check that greps the output for key-like values in URL-building code and fails the generation if found.

Expected output: future generated clients fail loudly at generation time instead of leaking at runtime.

## Variant phrasings

### api key leaked into logs from generated client

Steps 1-4 are the incident response; step 5 prevents the repeat. Do not skip rotation.

### generated client logged the full request on error

Same family. The error-logging code captured the URL with the key in it; fix the transport (step 2) and the logging (log headers redacted, never full URLs).

### docs example showed the key as a query param

Docs examples are often wrong about this. The provider's auth reference section is the authority; the quickstart example is not.

## Why it happens

Query-param auth is the easiest thing to write in generated code: string-concatenate the key onto the URL and it works. The agent optimizes for "the request succeeds," and it does. The leak is invisible at generation time because nothing in the request fails. The damage shows up later in the log aggregator, where full URLs are stored, indexed, and searchable by everyone with log access.

## Edge cases

- Providers that genuinely require query-param keys: rare, but they exist. If the provider's auth reference mandates it, scope the key tightly, shorten its lifetime, and make sure request logging strips query strings.
- The key is also in browser history or shared curl commands: rotation (step 3) covers this, since you cannot scrub someone's laptop.
- Webhook URLs with embedded secrets: same rule applies. Move the secret to a header; if the provider does not support it, rotate frequently and log-strip.
- The agent cached the old generated code: check for stale copies of the client (step 5's guard should also run against the existing codebase, not just new generations).

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_WZz4mGkY0hqsM0ekHoKZBA
