feat(cli)!: expire tokens by default#21783
Conversation
This adds a new `coder tokens expire` command that allows admins/owners
to immediately expire a token by ID. Unlike `coder tokens rm` which
deletes the token entirely, this preserves the token record for audit
trail purposes.
This is useful during incident response when a token needs to be
urgently revoked without direct database access.
The implementation includes:
- New API endpoint: PUT /api/v2/users/{user}/keys/{keyid}/expire
- New SDK method: ExpireAPIKey
- New CLI command: coder tokens expire <name|id|token>
- Audit logging for the expire action
Closes #21782
Co-Authored-By: Claude Opus 4.5 <[email protected]>
58aa3ec to
42b4846
Compare
|
Why not just use |
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as duplicate.
Good point - |
|
Could control it with a flag, perhaps by default? IDM, but I don't think we should have two commands that are almost identical in function |
Something like |
|
If the default behavior of |
This comment was marked as duplicate.
This comment was marked as duplicate.
This changes the default behavior of `coder tokens remove` to expire
tokens instead of deleting them, preserving the audit trail. Use
`--delete` to permanently delete a token.
Changes:
- Default behavior now expires tokens (preserves audit trail)
- Add `--delete` flag for permanent deletion
- Add `--include-expired` flag to `tokens ls` to show expired tokens
- Add PUT /users/{user}/keys/{keyid}/expire API endpoint
- Add ExpireAPIKey SDK method
Breaking change: Scripts using `coder tokens remove` will now expire
tokens instead of deleting them. Update to `coder tokens remove --delete`
for the previous behavior.
coder tokens expire command
This comment was marked as outdated.
This comment was marked as outdated.
docs/admin/users/sessions-tokens.md
Outdated
| ### Remove or expire a token | ||
|
|
||
| You can remove a token using the CLI or the API. By default, `coder tokens remove` | ||
|
|
dannykopping
left a comment
There was a problem hiding this comment.
LGTM 👍 a few minor comments
cli/tokens.go
Outdated
| cmd := &serpent.Command{ | ||
| Use: "remove <name|id|token>", | ||
| Aliases: []string{"delete"}, | ||
| Short: "Delete a token", |
There was a problem hiding this comment.
The short description is stale.
| Lifetime: time.Hour * 24 * 7, | ||
| }) | ||
| require.NoError(t, err) | ||
| keyID := strings.Split(res.Key, "-")[0] |
There was a problem hiding this comment.
Not something for this PR, but it bugs me that we don't have a parser for our API key format. We should be hiding this implementation detail behind a method on the Key.
Documentation CheckUpdates Needed
Previously Completed
SummaryThe documentation has been mostly updated, but contains an inaccuracy about expired token visibility that contradicts the actual CLI behavior (expired tokens are hidden by default, not visible). Automated review via Coder Tasks |
| Aliases: delete, rm | ||
|
|
||
| Remove a token by expiring it. Use --delete to permanently delete the token | ||
| instead, which removes the audit trail. |
Summary
Updates the
coder tokens rmcommand to immediately expire a token by ID, preserving the token record for audit trail purposes. Tokens can still be deleted by passing--delete.Problem
During an incident on dev.coder.com, operators needed to urgently expire an API key that was stuck in a hot loop. The only way to do this was via direct database access:
This is not ideal for operators who may not have direct DB access or want to avoid manual SQL.
Solution
This PR adds:
PUT /api/v2/users/{user}/keys/{keyid}/expire- Sets the token'sexpires_atto nowExpireAPIKey(ctx, userID, keyID)coder tokens rm <name|id|token>now expires by default. You can still delete by passing the--deleteflag. Thecoder tokens listcommand now also hides expired tokens by default. You can--include-expiredif needed to include them.Test plan
Closes #21782
🤖 Generated with Claude Code