Summary
Add a key rotation skill that detects when signing keys are older than 30 days and walks the agent through rotating them — generating a new key, publishing it to the JWKS, and scheduling removal of the old key.
Motivation
Keys currently have no expiration or rotation guidance. The aauth.created field and date-stamped kid format (e.g. 2026-04-09_a3f) already encode the creation date, but nothing acts on it. Long-lived signing keys are a security risk; routine rotation should be a first-class operation.
Proposed Behavior (Skill Instructions)
The rotation skill should guide an agent (or be invoked by a user) through these steps:
1. Check key age and clean up retired keys
- Read the agent's config (
~/.aauth/config.json) and enumerate registered keys
- Fetch the published JWKS and check for any keys with a
removeAfter timestamp that has passed — remove those keys from the JWKS
- Parse the creation date from the
kid (format YYYY-MM-DD_HHH) or from aauth.created in the published JWK
- Flag any key older than 30 days as due for rotation
2. Verify ability to update published keys
- Resolve the agent's
jwks_uri (from aauth-agent.json or cached in config)
- Determine the hosting platform from config (
hosting field)
- Verify CLI access to the hosting platform (e.g.
gh authenticated for GitHub Pages, wrangler for Cloudflare, etc.)
- Confirm the JWKS file can be updated before proceeding — abort with guidance if not
3. Generate a new key
- Use existing key generation (
generateKey) on all available backends (hardware preferred, matching current setup)
- Register the new key in the agent config
4. Update the JWKS file
- Add the new public key to the
jwks.json keys array
- Annotate the old key with a retirement note in its
aauth metadata:
"aauth": {
"device": "yubikey-otp+fido+ccid-0775",
"created": "2026-03-01",
"removeAfter": "2026-04-16T00:00:00Z"
}
The removeAfter timestamp should be 48 hours from the rotation time, giving relying parties time to see tokens signed with the old key
- Push the updated JWKS to the hosting platform
5. Post-rotation
- Log a summary: which key was rotated, what backend, old kid → new kid, and when the old key can be removed
Implementation Notes
- Skill file:
local-keys/skills/rotate.md
- Key age threshold (30 days) could be a constant in the skill or configurable later
- The 48-hour retirement window balances security with token lifetime (default 1h) plus clock skew
checkKeyAvailability() in resolve-key.ts already identifies which published keys are locally available — useful for finding keys that can no longer be rotated (device removed)
- Platform-specific push logic already exists in platform skills (
github-pages.md, cloudflare-pages.md, etc.) — rotation skill should reference those
Out of Scope (for now)
- Automatic unattended rotation (cron/scheduled) — this is an interactive skill
- Revoking keys before the 48-hour window (emergency rotation is a separate concern)
- Multi-agent coordinated rotation
Summary
Add a key rotation skill that detects when signing keys are older than 30 days and walks the agent through rotating them — generating a new key, publishing it to the JWKS, and scheduling removal of the old key.
Motivation
Keys currently have no expiration or rotation guidance. The
aauth.createdfield and date-stampedkidformat (e.g.2026-04-09_a3f) already encode the creation date, but nothing acts on it. Long-lived signing keys are a security risk; routine rotation should be a first-class operation.Proposed Behavior (Skill Instructions)
The rotation skill should guide an agent (or be invoked by a user) through these steps:
1. Check key age and clean up retired keys
~/.aauth/config.json) and enumerate registered keysremoveAftertimestamp that has passed — remove those keys from the JWKSkid(formatYYYY-MM-DD_HHH) or fromaauth.createdin the published JWK2. Verify ability to update published keys
jwks_uri(fromaauth-agent.jsonor cached in config)hostingfield)ghauthenticated for GitHub Pages,wranglerfor Cloudflare, etc.)3. Generate a new key
generateKey) on all available backends (hardware preferred, matching current setup)4. Update the JWKS file
jwks.jsonkeysarrayaauthmetadata:removeAftertimestamp should be 48 hours from the rotation time, giving relying parties time to see tokens signed with the old key5. Post-rotation
Implementation Notes
local-keys/skills/rotate.mdcheckKeyAvailability()inresolve-key.tsalready identifies which published keys are locally available — useful for finding keys that can no longer be rotated (device removed)github-pages.md,cloudflare-pages.md, etc.) — rotation skill should reference thoseOut of Scope (for now)