Flow
Six checks, one call, after the swap
1Key is real
Now asked of the provider. Still checked.
2Revoked
Provider knows, but each server's cache keeps accepting the key for a few minutes.
3Expired
Left to the provider. My code no longer has its own answer.
4Allowed address
Gone. The address is passed in and never read.
5Scopes
Written to a debug log and ignored. Any valid key passes.
6Which key sent it
Gone from incoming telemetry, because validation returns no key id.
Each ingestion route in my telemetry API still says the caller needs write access. Since I moved my API keys to a hosted login provider, nothing checks it.
One call, six checks
My old keys lived in my own table. When a key came in, my code checked six things:
- Is the key real?
- Is it revoked?
- Is it expired?
- Is it sent from an allowed address?
- Does it have the scopes the route asks for? Scopes are the list of things a key may do.
- Which key sent this, so the data can be tagged with it?
All six sat behind one function call, so when I swapped the call, all six went with it. The new code only handles the first one directly.
The scope list that checks nothing
The new code asks the provider if the key is valid. The routes still pass a scope list, and the code still accepts it. But the part that said no is gone. Nothing else uses the list.
The scopes a route asks for are only written to a debug log.
A missing guard is easy to see. A guard that names a permission looks safe to me, to a reviewer and to the type checker. That's what makes it worse.
Right now it does little harm. All new keys are the same kind, and the only routes using this guard all ask for write. The risk is the next route. If I add a read-only or admin route, it will look locked and let any valid key in.
The cache and revoked keys
Valid keys are cached in each server process for a few minutes. The cache is keyed by the secret itself. The revoke route only knows the key's id, so it can't clear the entry. A revoked key keeps working on each server until its copy runs out. Role and plan changes wait just as long.
I'd key the cache by a hash of the secret and keep a map from key id to hash, so a revoke can find and drop the entry. Or I'd keep the cache short and write that delay down as the promise.
Rotation and lost tracking
The old revoke route checked that the key belonged to the caller's organization. The new one hands the id straight to the provider, which might check that, though I haven't confirmed it.
Rotation now creates a new key and then revokes the old one. If the second step fails, the caller gets an error and never sees the new key, while the old key keeps working.
Incoming telemetry also no longer records which key sent it, and the address restriction disappeared as well.
Delete the option, or refuse to boot
Either the server refuses to start when a route passes scopes it can't check, or the option gets deleted. I lean toward deleting it, and moving admin routes to normal logins instead of keys.
None of my changes are written yet. And I can't promise this code ever ran. The notes in the same commit list type errors on the very provider calls it depends on.