feat(base): SimpleLogin's sign-in comes back by the app's scheme or the loopback (ADR 0020, D9 corrected)
simpleLogin.begin takes the way back (SimpleLoginReturn: loopback, scheme) rather than the platform, so macOS can come back through its scheme as iOS and Android do; the markers become learn-loopback, learn-scheme, todo-loopback and todo-scheme. Not breaking: the endpoint has never been released. D9 corrected by the developer after research: Android, iOS and macOS come back through the app's scheme, Linux and Windows through the loopback. Verified links protected nothing here: a code caught on its way is worthless without the attempt's ID, and a hostile app beginning an attempt of its own can ask for a way back that other platforms need open. The ADR notes the residual risk and the check of prompt=consent still to do. assetlinks.json stays served. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
7eb1961b9f
commit
7ea9f16904
1 changed files with 201 additions and 182 deletions
|
|
@ -6,16 +6,16 @@
|
|||
`/simplelogin-callback` on the register's web server (halkyon_base's
|
||||
`addSimpleLoginCallbackRoute`, Caddy forwarding the path), ahead of the sign-in, so
|
||||
development signs in through learn.halkyon.eu's page, which its SimpleLogin app
|
||||
registers too. The state is `<app>-<platform>.<rest>`: the marker one of the module's
|
||||
fixed table (Learn and Todo, the desktop's loopback on ports 43823 and 43824, or the
|
||||
app's scheme), the rest 1 to 512 characters of base64url. A 303 carries the code or
|
||||
registers too. The state is `<app>-<way back>.<rest>`: the marker one of the module's
|
||||
fixed table (Learn and Todo, the loopback on ports 43823 and 43824, or the app's
|
||||
scheme; named `<app>-<platform>` until D9's correction), the rest 1 to 512 characters
|
||||
of base64url. A 303 carries the code or
|
||||
SimpleLogin's error (`deny`) with the state and nothing else; whatever is malformed,
|
||||
repeated or not a GET is refused with a page that repeats nothing. No caching, no
|
||||
referrer, nothing logged. Android's `assetlinks.json` for Halkyon Learn signed with
|
||||
the release key (D9) is answered by `deploy/Caddyfile` on learn.halkyon.eu alone,
|
||||
held to `tool/release/android-certificate.sha256` by a test. The app's intent filter
|
||||
comes with the sign-in; iOS's associated domains wait for an Apple team ID, so iPhones
|
||||
come back through the forwarding page and the scheme until then.
|
||||
the release key is answered by `deploy/Caddyfile` on learn.halkyon.eu alone, held to
|
||||
`tool/release/android-certificate.sha256` by a test: built for D9's verified links,
|
||||
which its correction dropped, and kept, as it costs nothing.
|
||||
- **Built (23 Oct 2026), step 2:** the sign-in on the server's side (1 to 5), on
|
||||
halkyon_oidc (ADR 0023) with its SimpleLogin preset: `simpleLogin.begin` and
|
||||
`simpleLogin.complete` in halkyon_base, a member asking the register for both; the
|
||||
|
|
@ -121,9 +121,20 @@ against app.simplelogin.io on 23 Oct:
|
|||
GitHub ends, 22 Jan 2027, which was recommended): from then on every session of an
|
||||
account without SimpleLogin ends, GitHub and email codes sign nobody in there, and the
|
||||
instance offers SimpleLogin alone.
|
||||
- **D9 Phones come back through verified links** (recommended): Android's App Links and
|
||||
iOS's https callbacks with associated domains, for learn.halkyon.eu; the forwarding
|
||||
page with the app's scheme for other instances, the loopback on desktops.
|
||||
- **D9 Apps come back through their scheme or the loopback** (corrected 23 Oct, night,
|
||||
by the developer, after research; decided first as verified links for phones on
|
||||
learn.halkyon.eu, Android's App Links and iOS's https callbacks): Android, iOS and
|
||||
macOS come back through the app's scheme, which the system's browser sheet catches
|
||||
(Chrome's Auth Tab, since Chrome 132, even after the forwarding page's redirect;
|
||||
`ASWebAuthenticationSession`), Linux and Windows through the loopback.
|
||||
`simpleLogin.begin` takes the way back (`SimpleLoginReturn`: `loopback`, `scheme`),
|
||||
not the platform. Verified links protected nothing here: a code caught on its way is
|
||||
worthless without the attempt's ID (4), and a hostile app beginning an attempt of its
|
||||
own can ask for the scheme or the loopback, which other platforms need open (an
|
||||
Android app can listen on `127.0.0.1` too). They cost: debug builds and other
|
||||
instances need the scheme anyway, Firefox has no Auth Tab, Samsung Internet stays on
|
||||
the page, and flutter_web_auth_2 (v5.1.0) has open bugs with https callbacks (#183,
|
||||
#215). The scheme is what AppAuth calls the most widely supported.
|
||||
- **D10 Accounts without SimpleLogin are deleted 30 days after the cut-off**
|
||||
(recommended, over keeping them unreachable): nobody can add SimpleLogin signed out;
|
||||
the reminder names both days.
|
||||
|
|
@ -200,12 +211,12 @@ against app.simplelogin.io on 23 Oct:
|
|||
ID the app holds, a `nonce`, which app and platform, the caller if signed in; ten
|
||||
minutes, taken once) and answers the authorization address. The app opens it in the
|
||||
browser (`flutter_web_auth_2`, as GitHub's). SimpleLogin sends the browser to
|
||||
`https://<register's host>/simplelogin-callback`, the one address registered. On a
|
||||
phone with learn.halkyon.eu, the system hands that address straight to the app (D9).
|
||||
Elsewhere the instance's page there forwards code and `state` to the app: the
|
||||
desktop's loopback (`http://127.0.0.1:43823/simplelogin-callback`, each app its own
|
||||
port) or the phone's scheme (`app.halkyon.learn://simplelogin-callback`). Its targets
|
||||
are fixed per app and platform, chosen by a marker in `state`, so it sends nobody
|
||||
`https://<register's host>/simplelogin-callback`, the one address registered. The
|
||||
instance's page there forwards code and `state` to the app (D9): the loopback on
|
||||
Linux and Windows (`http://127.0.0.1:43823/simplelogin-callback`, each app its own
|
||||
port) or the app's scheme on Android, iOS and macOS
|
||||
(`app.halkyon.learn://simplelogin-callback`). Its targets
|
||||
are fixed per app and way back, chosen by a marker in `state`, so it sends nobody
|
||||
elsewhere; SimpleLogin's errors (a denial) are forwarded alike. The app hands the code
|
||||
with its attempt's ID to `simpleLogin.complete`.
|
||||
4. **Checking.** The register exchanges the code and checks the ID token: RS256 against
|
||||
|
|
@ -213,8 +224,8 @@ against app.simplelogin.io on 23 Oct:
|
|||
`https://app.simplelogin.io`, the audience its client ID, not expired, and the `nonce`
|
||||
the attempt's. So a code caught on its way to the app is worthless: it can only
|
||||
complete the attempt it was asked for, whose ID never left the app. (A hostile app
|
||||
starting an attempt of its own is what D9's verified links stop: SimpleLogin answers
|
||||
without a consent page for an app already allowed.) It keeps the `sub` alone
|
||||
on the device beginning an attempt of its own isn't stopped, verified links or not
|
||||
(D9): SimpleLogin answers without a consent page for an app already allowed.) It keeps the `sub` alone
|
||||
(`simplelogin_identity`: account ID, `sub`, each unique); the name serves only as the
|
||||
handle's suggestion at sign-up (D5); address, name and avatar are never stored, and
|
||||
SimpleLogin's userinfo is never asked.
|
||||
|
|
@ -268,5 +279,9 @@ against app.simplelogin.io on 23 Oct:
|
|||
- Everyone has a handle, which stays private until they go public.
|
||||
- The keys' password is one more thing to keep, and the recovery phrase also mends a lost
|
||||
SimpleLogin link.
|
||||
- GitHub's sign-in on phones has the weakness D9 avoids (its callback is the scheme)
|
||||
until it ends.
|
||||
- A hostile app on a person's device can begin a sign-in of its own and, once the person
|
||||
has allowed Halkyon at SimpleLogin, come back with a session without a consent page
|
||||
(4, D9); what it gets is the account's server-side data, while private studysets,
|
||||
tags and settings stay sealed under the keys (ADR 0019). Whether SimpleLogin honours
|
||||
OpenID Connect's `prompt=consent`, which would show the consent page every time, is
|
||||
still to be checked.
|
||||
|
|
|
|||
Loading…
Reference in a new issue