Repository navigation
Secure cross-platform account linking #16
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or requestsecurityAuth, access control, privacy, secrets — needs human reviewAuth, access control, privacy, secrets — needs human review
Milestone
Description
Context
Tiers are tied to Discord IDs. For Pixel to recognise a member on Telegram (#17) or any future interactive platform, they have to prove that the new account belongs to the same person as a trusted Discord account. This is the most security-sensitive feature in the roadmap.
The identity doc sketches the flow:
- The person asks for a one-time link code from their (trusted) Discord account. The code is shown only to them.
- They redeem it in a private chat on the new platform.
- Codes:
- are high-entropy, short-lived and single-use
- are stored only as a hash
- are rate-limited
- are redeemed safely even if two attempts race
- Both accounts are notified when a link happens, with an easy way to undo it.
Depends on #15 (database).
Goal
People can securely link and unlink accounts across platforms. Linked accounts share one identity and tier.
Scope
- An identity model: a person with one or more platform accounts
- Commands: request a link code, redeem it, unlink, and show linked accounts in
/whoami - Tiers: identity resolution works through linked accounts, so a member's Telegram account resolves to their tier
- Audit: an audit record for every link and unlink, plus notifications to both accounts
- Abuse limits: rate limits per user, per code, and overall
Acceptance criteria
- Threat cases have tests:
- expired, reused and wrong codes
- redemption attempted in a group chat
- brute-force attempts
- two concurrent redemptions of the same code
- unlinking
- The plaintext code is never stored or logged
- A link never grants more than the trusted account's tier
-
docs/identity-and-access.mdis updated, plus an ADR - Security review by a second person before merge
Considerations
- The direction of trust: codes always go from an already-trusted account to the new one, never the reverse
- Should every person get a database identity when they first interact, or only when they link? Minimise stored data
/forget-me: deleting a person and their links (GDPR, Privacy notice and data retention (GDPR) #7)- Tiers come from Pixel's own data (the access store, Writable access store: members, friends and capabilities managed by admin commands #25), not from Discord roles, so a linked account simply shares that record. There's no role-freshness problem for people who only use Telegram. (This replaces the earlier idea of reading Discord roles, Discord role sync tier source #14, which was closed.)
- The access store is keyed by platform ID today (Discord). Linking is what lets other platforms' accounts point at the same person
References
docs/identity-and-access.md: Later phases
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestsecurityAuth, access control, privacy, secrets — needs human reviewAuth, access control, privacy, secrets — needs human review
Activity
NinjaLikesCheez commentedon Oct 7, 2026
Decision (2026-10-07): no database
The access files already allow several IDs per person (
ids: ["discord:…", "telegram:…"]), and the access store already writesmembers.yamlsafely and audits every change. So linking writes there, and Postgres (#15) isn't needed./linkon Discord: a private one-time code. It has about 40 bits of entropy, is kept only as a hash, in memory, is valid for 10 minutes and can be used once. Codes pending at a restart are lost, which is fine (Pixel is a single instance)./link <code>in a Telegram DM: redeeming it addstelegram:<id>to the person's entry through the access store, which audits it. Both accounts are told. It's rate-limited per Telegram user.admins.yamlaren't written at runtime, so an admin's Telegram ID is added by hand in both files./unlinkfrom either side. An admin can also remove an ID by editing the file.ha-doors. The runbook will cover unlinking, and/admin doors off, if an account is compromised.