66 lines
4.3 KiB
Markdown
66 lines
4.3 KiB
Markdown
|
|
# ADR 0016: One account across an instance's services
|
||
|
|
|
||
|
|
- **Status:** decided 19 Oct 2026, by the developer.
|
||
|
|
- **Builds on:** ADR 0010 (email sign-in), ADR 0011 (profile pages and the account domain),
|
||
|
|
ADR 0014 (halkyon_base), ADR 0015 (one repository).
|
||
|
|
- **Followed by:** ADR 0017 (password, TOTP and the keys), ADR 0018 (the agenda).
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
An operator may run several Halkyon services side by side (learn.example.com,
|
||
|
|
todo.example.com, later train. and meditate.). Each has its own server, database and
|
||
|
|
sessions, and until now its own accounts: the same address signed in to Learn and to
|
||
|
|
Todo reached two people, with two handles and two deletions.
|
||
|
|
|
||
|
|
The reason to join them is Todo as the agenda of all the others, both ways: Learn's cards
|
||
|
|
due today, Train's planned exercise and Meditate's session appear in Todo, and moving one
|
||
|
|
there moves it in the app it belongs to (ADR 0018). That needs one person behind them all.
|
||
|
|
Handles on the account domain (ADR 0011) need it too: two services handing out handles on
|
||
|
|
one domain would hand the same one to two people.
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
1. **Within one operator's instance only.** Across operators would need an OpenID Connect
|
||
|
|
provider with web sign-in pages, browser sessions and consent; not now.
|
||
|
|
2. **A register in one service's server.** halkyon_base runs in one of two modes. The
|
||
|
|
service the operator names holds the register (on learn.halkyon.eu, Learn's server: it
|
||
|
|
holds the identities and handles already, so nobody's account moves); the others are its
|
||
|
|
members and ask it. With a single service nothing changes: it is its own register.
|
||
|
|
3. **One account ID everywhere.** A member's own person (its `AuthUser`) takes the
|
||
|
|
register's account ID, so a deletion, a handle or an agenda item names the same person
|
||
|
|
in every service.
|
||
|
|
4. **Each app signs in itself.** Apps on one device can't read each other's sessions, so
|
||
|
|
Todo signs in on its own (today with an email code or GitHub, after ADR 0017 with the
|
||
|
|
password and TOTP) and reaches the same account: the member's server runs the sign-in by
|
||
|
|
asking the register (it mails the codes and resolves addresses and GitHub IDs), then
|
||
|
|
opens a session of its own for that account. As Proton's apps do.
|
||
|
|
5. **Trust between servers:** a secret the instance's services share (`instanceSecret`;
|
||
|
|
`INSTANCE_SECRET` in `deploy/.env`), sent with every call a member makes; members reach
|
||
|
|
the register at an address the operator gives (its address on the instance's own network
|
||
|
|
when on one host). Nothing a person's device sends can call the register as a member.
|
||
|
|
6. **Anonymous accounts stay per service.** Becoming identified (an address or GitHub
|
||
|
|
added) makes the anonymous person an account of the register under the same ID, or
|
||
|
|
switches to the account the identity belongs to, as linking and switching do today.
|
||
|
|
7. **Handles and profiles move into halkyon_base**, served by the register (the tables
|
||
|
|
unchanged, as the identities moved in ADR 0014): one handle per account on the account
|
||
|
|
domain, shown alike by every service. What fixes a handle (Learn: the first publish) is
|
||
|
|
the host's, told to the module.
|
||
|
|
8. **Deleting the account deletes it everywhere.** From any app: a member passes it to the
|
||
|
|
register, which deletes the account and its ways in, then tells every member to delete
|
||
|
|
that person's data; a member it can't reach is told again until it answers, and each
|
||
|
|
member also deletes, as it prunes, people the register no longer knows.
|
||
|
|
9. **Released apps:** the profile endpoints move, so the change rides on build 21's raise of
|
||
|
|
`minimumAppBuild` if it is through its checks by 22 Oct, else on a later release with a
|
||
|
|
raise of its own.
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
|
||
|
|
- The register's server learns when someone signs in to which service of the instance (the
|
||
|
|
privacy page says so); the services already share one operator.
|
||
|
|
- An operator running one service configures nothing new. One running several names the
|
||
|
|
register, gives every service the shared secret, and the register its members.
|
||
|
|
- If the register's server is down, members can't sign anyone in or create handles;
|
||
|
|
sessions already open keep working, and deletions wait.
|
||
|
|
- Learn's sign-in, profile and deletion code paths go through the module's register mode on
|
||
|
|
learn.halkyon.eu; Todo's through its member mode.
|
||
|
|
- Passwords, TOTP and end-to-end keys (ADR 0017) and the agenda (ADR 0018) build on this.
|