Problem
app/api/auth/stellar/link/route.ts validates and stores a public key but does not prove the signed-in user controls it. Relinking also lacks continuity proof.
Scope
- Add a short-lived, single-use challenge bound to user, operation, target account, network passphrase, nonce, and expiry.
- Verify a SEP-53-compatible signed message (or a documented equivalent).
- For relink, require the new key plus old-key proof or an audited recovery flow.
- Consume challenges atomically and audit link/relink/unlink attempts without logging reusable signatures.
- Keep normalized unique-account enforcement and avoid account-enumeration errors.
Acceptance criteria
- A valid but uncontrolled public key cannot be linked.
- Challenges are operation/network/account bound, expire, and cannot be replayed.
- Concurrent consumption produces one winner.
- Relink and recovery policies are explicit and auditable.
- API errors are stable and privacy-preserving.
Required tests
Valid/wrong signer, wrong network/user/operation, expiry, replay, concurrent consumption, duplicate-account races, relink, recovery, and log redaction.
Non-goals
Do not store custodial private keys or build unrelated wallet UI.
Problem
app/api/auth/stellar/link/route.tsvalidates and stores a public key but does not prove the signed-in user controls it. Relinking also lacks continuity proof.Scope
Acceptance criteria
Required tests
Valid/wrong signer, wrong network/user/operation, expiry, replay, concurrent consumption, duplicate-account races, relink, recovery, and log redaction.
Non-goals
Do not store custodial private keys or build unrelated wallet UI.