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:
1 parent
c86c63922a
commit
43a98b0972
17 files changed
+1271
-44
No files matched your search
@@ -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…`
|
||||
|
||||
Reference in new issue
Block a user