## What
API key validation applied a sliding-window expiry refresh to every key
type. Programmatic API tokens (created via `coder tokens create`, login
type `token`) had their `expires_at` extended to `now + lifetime` on
each authenticated request (with a ~1h debounce), so a token used within
its lifetime window never actually expired.
This restricts the sliding-window refresh to interactive login sessions
(password / OIDC / GitHub). Programmatic tokens now honor their fixed
`expires_at`.
## Why
A finite token `--lifetime` is expected to be a hard expiry. Silently
extending it on use defeats that expectation and prevents rotation of
long-lived automation credentials.
## Changes
- `coderd/httpmw/apikey.go`: skip the expiry refresh when `key.LoginType
== database.LoginTypeToken`.
- `coderd/httpmw/apikey_test.go`: regression test asserting a token's
expiry is not extended on use.
## Notes
- Interactive sessions are unaffected (they still slide while active).
- Tokens already extended are not retroactively shortened; this prevents
future extension.
<details>
<summary>Validation</summary>
- `go build ./coderd/httpmw/...`
- `go test ./coderd/httpmw/ -run TestAPIKey -count=1` (all pass,
including the new `TokenNoExpiryRefresh` and the interactive
`ValidUpdateExpiry`)
- `golangci-lint run ./coderd/httpmw/` (clean)
- Confirmed the new test fails without the production change and passes
with it.
</details>
---
🤖 Generated by Coder Agents on behalf of @jdomeracki-coder.