summaryrefslogtreecommitdiffstats
path: root/doc/auth.md
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2026-03-07 11:45:19 -0500
committerSam Anthony <sam@samanthony.xyz>2026-03-07 11:45:19 -0500
commit7c32f8a87889c8fdb8637243fd540061ea1a8539 (patch)
treefe5b5b42f3cfe74e755cf57419b7f3d3b6dd89bb /doc/auth.md
parent36381d86c6a690a7870ce360dad63be333361447 (diff)
downloadbuth-7c32f8a87889c8fdb8637243fd540061ea1a8539.zip
doc: simplify architecture, some notes
Got rid of client-side 9p, which was just silly bloat. Using HTTP exclusively on the client side now, with htmx. Combined auth and api servers into monolithic buthd, which translates http/9p between client and backend 9p servers. Added some implementation and security notes, and part of shopfs.
Diffstat (limited to 'doc/auth.md')
-rw-r--r--doc/auth.md57
1 files changed, 27 insertions, 30 deletions
diff --git a/doc/auth.md b/doc/auth.md
index a8aeb25..e509e44 100644
--- a/doc/auth.md
+++ b/doc/auth.md
@@ -1,50 +1,47 @@
# Authentication
-## Registration flow
+## Registration
This is how a new user registers himself in `authfs`, after which he can open sessions.
- Client `GET`s `shop./register.html`
-- Client enters username and password, `POST`s form to `auth./register`
-- `buthauth` server registers user in `authfs`
+- Client enters username and password, `POST`s form to `api./register`
+- `buthd` registers user in `authfs`
- Creates `/users/<username>/`
- If it already exists, the username is taken; return error to client
- Writes password to `/users/<username>/passwd`
- `authfs` ingests and hashes the password. Subsequent reads of `/users/<username>/passwdhash` will return the hash (`authfs` discards the cleartext password after it is hashed).
- If successful, client can now login to obtain a session
-## Login flow
+## Login
This is how a client authenticates itself and creates a _session_. A session gives the client a shopping cart and access to the checkout.
- Client `GET`s `shop./login.html`.
-- Client enters username and password (assume they already have an account).
-- Js or wasm script running in client generates a 256-bit session ID and injects it into the login form.
-- Client `POST`s the login form to `auth./login`
-- `buthauth` writes the password to `/users/<username>/login` in `authfs`
+- Client enters username and password.
+- JS script running in client generates a 256-bit session ID and injects it into the login form.
+- Client `POST`s the login form to `api./login`
+- `buthd` writes the password to `/users/<username>/login` in `authfs`
- If `/users/<username>/` doesn't exist, the username is invalid; fail the login
-- `buthauth` reads from `/users/<username>/login`.
+- `buthd` reads from `/users/<username>/login`
- If the password was correct, `authfs` returns a session ID corresponding to `/sessions/<id>/
- - Otherwise if the password was wrong, `authfs` returns `Rerror`. `buthauth` fails the login, returning an error to the client
-- `buthauth` returns a session cookie, containing the session ID, to the client (with proper security params: HttpOnly etc.)
+ - Otherwise if the password was wrong, `authfs` returns `Rerror`. `buthd` fails the login, returning an error to the client
+- `buthd` returns a session cookie containing the session ID to the client (with proper security params: HttpOnly etc.)
- Client includes the session cookie in subsequent requests, giving it elevated privileges.
On the client, session is a _session cookie_ (no expiry date). On the server, it should expire after `lastseen+t`. `authfs` periodically sweeps the sessions and removes old ones. `authfs` updates a sessions's last-seen time whenever it gets a request on `/sessions/<id>/*`.
-## API usage
-This is how a client accesses the 9P API once he's logged in (has a session cookie).
-- Client `GET`s `shop./foo.html`
- - Includes cookie in request
-- Httpd returns static page and scripts
-- Script opens websocket on `api./ws`
-- Browser sends cookie automatically in upgrade request
-- `buthapi` validates session (using cookie) by checking if `/sessions/<id>/` exists on `authfs`.
- - If not, the session is invalid, return 401
-- `buthapi` upgrades the websocket connection and serves 9P
-- Client uses ws/9p connection to access API
- - E.g. pressing "add to cart" button does `Tcreate /cart/sku123`
- - (will need to figure out how to wire this up with htmx/js and 9p js/wasm lib)
-
-## Logout flow
+Generate the session id on the client side to take advantage of the abundance of entropy there compared to on the server.
+
+## Logout
This is how a client destroys an active session on the server.
- Client clicks Logout button
-- Htmx `POST`s to `auth./logout`, includes the session cookie in the request
-- `buthauth` reads the session ID from the cookie
-- `buthauth` removes `/sessions/<id>` on `authfs`
-- `buthauth` returns a response header telling the client browser to destroy the session cookie.
+- htmx `POST`s to `api./logout`, includes the session cookie in the request
+- `buthd reads the session ID from the cookie
+- `buthd` removes `/sessions/<id>` on `authfs`
+- `buthd` returns a response header telling the client browser to destroy the session cookie.
+
+## TODO
+- Allow the user to register an email for password recovery?
+- Document changing password: buthd writes to `/users/<username>/passwd`
+
+## Implementation notes
+
+Don't leave 9p connections laying around. Open a new one for each http request as required. This is to avoid attacks like the following.
+Suppose buthd has a single connection to authfs that it uses for every http connection. Alice (the attacker) and Bob are both trying to login as `bob`. Alice's connection writes a junk password to `/users/bob/login`. Bob's connection writes the correct password. Alice's connection reads `login`, obtaining the session ID, as does Bob's connection. Now Alice has Bob's session ID and can act as Bob. This is bad.