A second way in: signing in through an identity provider

OpenID Connect, off unless four settings are present. It is a second way to
the same token the password login mints — every route and the WebSocket
still know only a signed JWT — which is why it fits in one file and needs no
new dependency: Node imports a JWK itself, so checking an ID token is a
signature and five claims.

Authorization Code with PKCE, exchanged on the server so the client secret
stays there. The browser comes home with a one-time ticket rather than the
token, because a token in a redirect URL sits in the history, in the proxy's
log and in the referrer of the next request.

Somebody the app has not seen gets an account; an account that already
exists under that name is linked to the identity rather than duplicated, by
subject from then on. Never an administrator. An account made this way has
no password here, and the interface stops offering one — but an admin can
still set one, which is the way back in if the provider is ever gone.

The suite signs in at a provider of its own that signs real RS256 tokens,
and holds down the four ways the journey must fail as well as the way it
must work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-18 16:38:24 +02:00
1 parent c86c63922a
commit 43a98b0972
17 files changed
+1271 -44

No files matched your search

+33
View File
@@ -14,6 +14,39 @@ a rebuild is not bit-identical.
---
## 2026-08-18 — A second way in
**Images** — web `sha256:232982cb…`, server `sha256:5ed577b1…`
The server image changed: OpenID Connect, and an `oidc_sub` column on users.
- **Signing in through an identity provider**, when one is configured — issuer,
client id and secret, and the address this app is reached at; without them
nothing about it appears anywhere. It is a second way to the *same* token the
password login mints, which is why it fits in one file and needs no new
dependency: Node imports a JWK itself, so checking an ID token is a signature
and five claims.
- **The browser is handed a one-time ticket, never the token.** The code is
exchanged on the server, so the client secret stays there, and a token in a
redirect URL would otherwise sit in the history, in the proxy's log and in the
referrer of the next request. The ticket is good for a minute and for one use.
- **An account is made for somebody the app has not seen**, and an account that
already exists under that name is linked to the identity rather than
duplicated — by subject from then on, so either side can be renamed. Never an
administrator: those rights are granted in the app, and a group at the provider
must not be a way around it.
- **Both doors stay open.** An account made this way has no password here at all
— the interface stops offering to change one and the login route refuses it as
it refuses a wrong one, at the same speed — but an administrator can still set
one, which is the way back in the day the provider is unreachable.
- **A suite that signs in at a provider of its own** (`e2e/oidc.mjs`), which
signs real RS256 tokens with a key InkNote fetches and checks. It holds down
the four ways the journey must fail as well as the way it must work: a refusal,
a replayed ticket, a token signed with an unpublished key, and one addressed to
another client.
---
## 2026-08-17 — Quotes that hold more than a sentence, and one list of marks
**Images** — web `sha256:30f67832…`, server `sha256:6ffe4b58…`