Feature: Key Rotation #27
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom#27
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from GitHub issue icub3d/decentcom#27
Original Author: @icub3d
Original Date: 2026-04-15T14:15:56Z
Feature: Key Rotation
Overview
Key rotation allows a user to migrate their identity from an old Ed25519 key pair to a new one. The user signs a rotation declaration with the old key, proving they control the current identity, and the server migrates all associated data (membership, roles, messages) to the new public key. The old key is added to a revocation list so it cannot be used for authentication.
Background
The identity design doc (
docs/design/identity.md) describes the rotation approach: the user signs a{new_pubkey, timestamp, reason}declaration with the old key, servers accept the declaration and migrate the identity, and the old key is revoked. The doc raises an open question about a time-delay grace period for rotation. Key rotation is the hardest problem in the identity model because it requires server cooperation and cannot be done if the old private key is lost (that scenario requires creating a new identity entirely).Depends on:
identity(feature #4),auth(feature #5),device-keys(feature #15), all Phase 1 and Phase 2 features.Requirements
Design
API / Interface Changes
REST endpoints:
/api/v1/identity/rotate/api/v1/identity/revocationsPOST
/api/v1/identity/rotaterequest body:Response (success):
Tauri IPC commands:
key_rotatereason: stringResult<RotationResult, Error>key_rotation_statusResult<RotationHistory, Error>Data Model Changes
New table:
revoked_keysidold_pubkeynew_pubkeydeclarationrotated_atModified
userstable: Thepubkeycolumn is updated in place. The old pubkey is only preserved in therevoked_keystable.Modified
device_keystable: All device delegation certificates for the old master key are deleted (they were signed by the old key and are no longer valid).Component Changes
Server (
server/):server/src/routes/identity.rs— new route module with therotateandrevocationsendpointsserver/src/models/revocation.rs— new model:RevokedKeystruct, rotation declaration parsing and signature verificationserver/src/storage/trait.rs— extendUserStoretrait withrotate_key()andis_key_revoked()methodsserver/src/storage/sqlite/users.rs— implementrotate_key(): updateusers.pubkey, insert intorevoked_keys, delete device keys, invalidate sessionsserver/src/storage/postgres/users.rs— same implementation for PostgreSQL (if postgres feature is already built)server/src/auth.rs— check revocation list during authentication; return specific error for revoked keysserver/src/gateway/handler.rs— disconnect active WebSocket sessions for the old key after rotationClient Tauri core (
client/src-tauri/src/):client/src-tauri/src/commands/key_rotation.rs— Tauri IPC command handler: generate new key pair, construct and sign the rotation declaration, call the server endpoint, update the local keychainclient/src-tauri/src/crypto/rotation.rs— rotation declaration construction and signing logicclient/src-tauri/src/keystore.rs— extend withrotate_key()method that generates new key, stores it, and archives the old key locallyClient React (
client/src/):client/src/components/settings/KeyRotation.tsx— new component: rotation UI with reason input, confirmation dialog, progress indicator, success/error feedbackclient/src/components/settings/SecuritySettings.tsx— extend to include key rotation sectionTask List
Phase A: Server Rotation Handling
revoked_keystable in SQLite and PostgreSQL migration filesserver/src/models/revocation.rs—RotationDeclarationstruct with signature verificationUserStoretrait withrotate_key(old_pubkey, new_pubkey, declaration)andis_key_revoked(pubkey)methodsrotate_key()for SQLite: updateusers.pubkey, insertrevoked_keys, deletedevice_keysfor old master, invalidate sessionsis_key_revoked()for SQLiteserver/src/routes/identity.rswith therotateendpoint: validate declaration, verify signature, callrotate_key()revocationsendpoint to list revoked keysserver/src/auth.rsto check revocation list and return a specific error for revoked keysPhase B: Client Rotation Logic
client/src-tauri/src/crypto/rotation.rs— build rotation declaration bytes and sign with old keyclient/src-tauri/src/commands/key_rotation.rs—key_rotatecommand: generate new key pair, sign declaration, submit to server, update local keychain on successrotate_key(): generate new key pair, store new key, keep a local record of the old public key for referencePhase C: Client UI
client/src/components/settings/KeyRotation.tsx— rotation form with reason field, warning about device key revocation, confirmation dialogclient/src/components/settings/SecuritySettings.tsxTest List
rotate_key()updates the user's pubkey in the databaserotate_key()inserts a record intorevoked_keysrotate_key()deletes device keys associated with the old master keyis_key_revoked()returns true for a revoked key and false for an active keyOpen Questions