diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-17 17:38:14 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-17 17:38:14 +0200 |
| commit | f23e8e51e4b8bc03d6109081fe048af1782e1f4e (patch) | |
| tree | 29772398ef6cd488d50b032358b468eece0f2add /docs | |
| parent | 6562665c80f96f30fef95af83a0abcf71f41795f (diff) | |
| download | meshbay-0.5.tar.gz | |
docs: sessions renew themselves, and two faults of the same shape0.5
USERGUIDE said an hour in five places and presented renewal as something the
reader does with curl. Both are now wrong: it is four hours, the web app renews
for itself, and the endpoint rotates — so anyone driving it by hand has to store
the refresh token that comes back, or their next call revokes the family.
Also corrects what the token's life actually bounds. It is not how long a
revocation takes: the hub reloads the account on every request and refuses a
suspended one at once, and it pushes signed revocations to nodes. What remains
is a leaked token on an account still in good standing, which is the reason to
keep the number small.
Two lessons in CLAUDE.md. A rotated refresh token has to be stored or it is
spent once. And an effect keyed on a value that used to be constant: the WebRTC
dial listed `token` among its dependencies, harmless while a token only ever
expired, fatal once the session renewed itself — it tore the connection down
mid-handshake and the node waited for ever. That and the hook declared after its
own dependency are the same shape, and worth naming as one: code that reads
correctly on its own and is wrong against the component lifecycle.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/USERGUIDE.md | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md index abfc404..7bd695b 100644 --- a/docs/USERGUIDE.md +++ b/docs/USERGUIDE.md @@ -98,10 +98,10 @@ POST /v1/users/register POST /v1/users/login {"username": "yourname", "password": "yourpassword"} → { - "access_token": "JWT (Ed25519, 1 hour validity)", + "access_token": "JWT (Ed25519, 4 hour validity)", "refresh_token": "opaque 256-bit token (30 days)", "token_type": "bearer", - "expires_in": 3600, + "expires_in": 14400, } ``` @@ -117,12 +117,20 @@ curl -s -X POST https://meshbay.org/v1/users/login \ ### Token refresh -Access tokens are valid for 1 hour. When one expires, use the refresh token to get a new one without re-entering your password: +Access tokens are valid for 4 hours. **The web app does this for itself** — it +renews ten minutes before expiry, on returning to the tab, and on any 401, then +replays the request. Nobody should meet an expired token in the browser; what +follows is for other clients. + +The endpoint **rotates**: it revokes the refresh token you present and returns a +new one, so store the replacement. Presenting a revoked token is treated as +theft and revokes the whole family, which is a full sign-out. ``` POST /v1/users/token/refresh {"refresh_token": "your-refresh-token"} -→ {"access_token": "new JWT", "token_type": "bearer", "expires_in": 3600} +→ {"access_token": "new JWT", "refresh_token": "USE THIS NEXT TIME", + "token_type": "bearer", "expires_in": 14400} ``` ```bash @@ -131,7 +139,13 @@ curl -s -X POST https://meshbay.org/v1/users/token/refresh \ -d '{"refresh_token":"YOUR_REFRESH_TOKEN"}' ``` -Refresh tokens are valid for 30 days and can be immediately invalidated by the hub on account compromise. Revoking the refresh token means the next access token renewal will fail; any active access token expires within 1 hour at most. +Refresh tokens are valid for 30 days — that is the session — and can be +invalidated by the hub at once on account compromise. Revoking one means the +next renewal fails; an access token already issued keeps working for up to 4 +hours. That window is not the whole story: the hub reloads the account on every +request and refuses a suspended one immediately, and it pushes signed +revocations to nodes, so suspending an account or revoking a membership takes +effect at once regardless of the token's remaining life. ### Access token structure @@ -146,7 +160,7 @@ The JWT payload contains: | `groups` | The `group_id`s you are a member of, for node-side authorization | | `scope` | `user` for a browser, `node` for a daemon | | `iat` | Issued at (Unix timestamp) | -| `exp` | Expires at (Unix timestamp, 1 hour from issue) | +| `exp` | Expires at (Unix timestamp, 4 hours from issue — `[jwt] access_token_ttl`) | The token carries **no public key of yours**. It used to carry `pk_user`, and a node recorded that key as the uploader of a file — which meant the party issuing tokens @@ -166,7 +180,7 @@ What deletion does: - Releases the username — someone else may register it afterwards - Clears the email and password hash, and drops the node linking key - Removes group memberships, notifications and refresh tokens -- Refuses any access token still in its hour of validity, immediately +- Refuses any access token still within its validity, immediately What deletion does **not** do: @@ -867,7 +881,7 @@ Two layers: - `jti` (UUID4) is mandatory in every token — prevents replay (Ed25519 signing is deterministic; without `jti`, two tokens issued in the same second are byte-for-byte identical) and enables individual revocation - Nodes verify JWTs offline using the hub's cached public key — no hub roundtrip, no hub downtime dependency -- Revocation: hub invalidates refresh token → next access token renewal fails → node access expires within 1 hour. For immediate revocation: hub adds `jti` to a denylist that nodes periodically fetch +- Revocation: hub invalidates refresh token → next access token renewal fails → node access expires within the access token's life. For immediate revocation: hub adds `jti` to a denylist that nodes periodically fetch ### What node compromise exposes @@ -961,7 +975,12 @@ These logs are not used for any purpose other than responding to legal requests. **Symptom:** node returns 401, error says "expired" or "Token signature expired". -**Fix:** your access token is over 1 hour old. Refresh it: +In the web app this should not happen: it renews before expiry and retries once +on a 401. If you see it there, the renewal path itself is broken — check the +browser console rather than the token. + +**Fix (other clients):** your access token is over 4 hours old. Refresh it, and +**keep the refresh token that comes back** — the one you sent is now revoked: ```bash curl -s -X POST https://meshbay.org/v1/users/token/refresh \ |