DID:PLC Rotation Keys: How the 72-Hour Recovery Window Works
DID:PLC uses a sophisticated key rotation system. Every account has 1-5 rotation keys that control the identity. Understanding how these keys work is essential for securing your ATProto account.
Key Types and Priority
DID:PLC supports two elliptic curve algorithms:
- secp256k1 (Bitcoin/Ethereum curve)
- P-256 (NIST standard, YubiKey compatible)
Keys are stored in priority order. Index 0 has the highest authority. Lower index means higher authority.
A typical setup:
rotationKeys[0] = your offline backup key (highest priority)
rotationKeys[1] = your PDS operational key (lower priority)
Any key can sign operations. But higher-priority keys can override operations signed by lower-priority keys.
The 72-Hour Recovery Window
This is the core security mechanism.
When an operation is accepted by the PLC directory, a 72-hour clock starts. During this window, a higher-priority key can submit a recovery operation that forks from before the malicious change, effectively nullifying it.
After 72 hours, operations become final.
How Recovery Works
Scenario: Your PDS goes rogue and removes your backup key.
- PDS submits operation removing your key
- You detect this within 72 hours
- You sign a new operation with your backup key (higher priority)
- Your operation points to the state before the attack
- PLC directory accepts your operation and nullifies the PDS's change
The math is simple: if your key has a lower index than the attacker's key, and you act within 72 hours, you recover.
Practical Security
Adding your own rotation key:
const creds = await agent.com.atproto.identity.getRecommendedDidCredentials();
const { token } = await agent.com.atproto.identity.requestPlcOperationSignature();
await agent.com.atproto.identity.signPlcOperation({
token,
rotationKeys: [
'did:key:zQ3sh...YourKey', // Your key first (highest priority)
...creds.rotationKeys // Existing keys
]
});
Storage options:
- YubiKey (P-256) - keys never leave hardware
- Cold storage - air-gapped, metal/paper backup
- Password manager - convenient, lower security
Best practice: Your highest-priority key should never be online.
Monitoring
Monitor your DID for unauthorized changes:
# urlwatch config
url: "https://plc.directory/did:plc:your_did/log/audit"
filter:
- diff: true
- shell: "jq '.[-1]'"
Or use the firehose:
firehose.on('identity', (event) => {
if (event.did === 'did:plc:your_did') {
sendAlert(event);
}
});
Attack Scenarios
PDS compromised:
- If you have a higher-priority key: recoverable within 72 hours
- If PDS key is highest priority: irrecoverable
Rotation key leaked:
- If you have other secure keys: rotate out the leaked key within 72 hours
- If all keys leaked: account compromised
PLC directory malicious:
- Cannot forge signatures
- Can reject operations (DoS)
- Can serve wrong forks
- Mitigation: use read replicas
Key Takeaways
- Always add your own rotation key at index 0
- Store that key offline or in hardware
- Monitor your DID for changes
- You have 72 hours to recover from most attacks
- After 72 hours, you're stuck with whatever changes were made
The 72-hour window is your safety net. Use it wisely.