docs: document register/login and dual authentication model
All checks were successful
check / check (push) Successful in 1m8s
All checks were successful
check / check (push) Successful in 1m8s
Update README to accurately describe the authentication model: - Anonymous sessions via POST /api/v1/session (no account required) - Optional account registration via POST /api/v1/register (nick + password) - Login to registered accounts via POST /api/v1/login Sections updated: - Identity & Sessions: renamed from 'No Accounts' to 'Dual Authentication Model' - API Reference: added /register and /login endpoint documentation - Security Model: added password hashing (bcrypt) details - Design Principles: changed 'No accounts' to 'Accounts optional' - Schema: updated from outdated 'users' table to actual sessions/clients tables - Session Lifecycle: added registered account flow diagram - Client Development Guide: added register/login curl examples - Multi-Client Model: documented login as the multi-client mechanism - Data Lifecycle: documented session/client persistence behavior
This commit is contained in:
269
README.md
269
README.md
@@ -113,8 +113,9 @@ mechanisms or stuffing data into CTCP.
|
|||||||
Everything else is IRC. `PRIVMSG`, `JOIN`, `PART`, `NICK`, `TOPIC`, `MODE`,
|
Everything else is IRC. `PRIVMSG`, `JOIN`, `PART`, `NICK`, `TOPIC`, `MODE`,
|
||||||
`KICK`, `353`, `433` — same commands, same semantics. Channels start with `#`.
|
`KICK`, `353`, `433` — same commands, same semantics. Channels start with `#`.
|
||||||
Joining a nonexistent channel creates it. Channels disappear when empty. Nicks
|
Joining a nonexistent channel creates it. Channels disappear when empty. Nicks
|
||||||
are unique per server. There are no accounts — identity is a key, a nick is a
|
are unique per server. Identity starts with a key — a nick is a display name.
|
||||||
display name.
|
Accounts are optional: you can create an anonymous session instantly, or
|
||||||
|
register with a password to persist your identity across sessions.
|
||||||
|
|
||||||
### On the resemblance to JSON-RPC
|
### On the resemblance to JSON-RPC
|
||||||
|
|
||||||
@@ -148,16 +149,43 @@ not arbitrary choices — each one follows from the project's core thesis that
|
|||||||
IRC's command model is correct and only the transport and session management
|
IRC's command model is correct and only the transport and session management
|
||||||
need to change.
|
need to change.
|
||||||
|
|
||||||
### Identity & Sessions — No Accounts
|
### Identity & Sessions — Dual Authentication Model
|
||||||
|
|
||||||
There are no accounts, no registration, no passwords. Identity is a signing
|
The server supports two authentication paths: **anonymous sessions** for
|
||||||
key; a nick is just a display name. The two are decoupled.
|
instant access, and **optional account registration** for persistent identity.
|
||||||
|
|
||||||
|
#### Anonymous Sessions (No Account Required)
|
||||||
|
|
||||||
|
The simplest entry point. No registration, no passwords.
|
||||||
|
|
||||||
- **Session creation**: client sends `POST /api/v1/session` with a desired
|
- **Session creation**: client sends `POST /api/v1/session` with a desired
|
||||||
nick → server assigns an **auth token** (64 hex characters of
|
nick → server assigns an **auth token** (64 hex characters of
|
||||||
cryptographically random bytes) and returns the user ID, nick, and token.
|
cryptographically random bytes) and returns the user ID, nick, and token.
|
||||||
- The auth token implicitly identifies the client. Clients present it via
|
- The auth token implicitly identifies the client. Clients present it via
|
||||||
`Authorization: Bearer <token>`.
|
`Authorization: Bearer <token>`.
|
||||||
|
- Anonymous sessions are ephemeral — when the session expires or the user
|
||||||
|
QUITs, the nick is released and there is no way to reclaim it.
|
||||||
|
|
||||||
|
#### Registered Accounts (Optional)
|
||||||
|
|
||||||
|
For users who want persistent identity across sessions:
|
||||||
|
|
||||||
|
- **Registration**: client sends `POST /api/v1/register` with a nick and
|
||||||
|
password (minimum 8 characters) → server creates a session with the
|
||||||
|
password hashed via bcrypt, and returns the user ID, nick, and auth token.
|
||||||
|
- **Login**: client sends `POST /api/v1/login` with nick and password →
|
||||||
|
server verifies the password against the stored bcrypt hash and creates a
|
||||||
|
new client token for the existing session. This enables multi-client
|
||||||
|
access: logging in from a new device adds a client to the existing session
|
||||||
|
rather than creating a new one, so channel memberships and message queues
|
||||||
|
are shared.
|
||||||
|
- Registered accounts cannot be logged into via `POST /api/v1/session` —
|
||||||
|
that endpoint is for anonymous sessions only.
|
||||||
|
- Anonymous sessions (created via `/session`) cannot be logged into via
|
||||||
|
`/login` because they have no password set.
|
||||||
|
|
||||||
|
#### Common Properties (Both Paths)
|
||||||
|
|
||||||
- Nicks are changeable via the `NICK` command; the server-assigned user ID is
|
- Nicks are changeable via the `NICK` command; the server-assigned user ID is
|
||||||
the stable identity.
|
the stable identity.
|
||||||
- Server-assigned IDs — clients do not choose their own IDs.
|
- Server-assigned IDs — clients do not choose their own IDs.
|
||||||
@@ -165,11 +193,14 @@ key; a nick is just a display name. The two are decoupled.
|
|||||||
in the token, no client-side decode. The server is the sole authority on
|
in the token, no client-side decode. The server is the sole authority on
|
||||||
token validity.
|
token validity.
|
||||||
|
|
||||||
**Rationale:** IRC has no accounts. You connect, pick a nick, and talk. Adding
|
**Rationale:** IRC has no accounts. You connect, pick a nick, and talk.
|
||||||
registration, email verification, or OAuth would solve a problem nobody asked
|
Anonymous sessions preserve that simplicity — instant access, zero friction.
|
||||||
about and add complexity that drives away casual users. Identity verification
|
But some users want to keep their nick across sessions without relying on a
|
||||||
is handled at the message layer via cryptographic signatures (see
|
bouncer or nick reservation system. Optional registration with password
|
||||||
[Security Model](#security-model)), not at the session layer.
|
solves this without adding friction for casual users: if you don't want an
|
||||||
|
account, don't create one. Identity verification at the message layer via
|
||||||
|
cryptographic signatures (see [Security Model](#security-model)) remains
|
||||||
|
independent of account registration.
|
||||||
|
|
||||||
### Nick Semantics
|
### Nick Semantics
|
||||||
|
|
||||||
@@ -207,12 +238,12 @@ User Session
|
|||||||
└── Client C (token_c, queue_c)
|
└── Client C (token_c, queue_c)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Current MVP note:** The current implementation creates a new user (with new
|
**Multi-client via login:** The `POST /api/v1/login` endpoint adds a new
|
||||||
nick) per `POST /api/v1/session` call. True multi-client (multiple tokens
|
client to an existing registered session, enabling true multi-client support
|
||||||
sharing one nick/session) is supported by the schema (`client_queues` is keyed
|
(multiple tokens sharing one nick/session with independent message queues).
|
||||||
by user_id, and multiple tokens can point to the same user) but the session
|
Anonymous sessions created via `POST /api/v1/session` always create a new
|
||||||
creation endpoint does not yet support "add a client to an existing session."
|
user with a new nick. A future endpoint to "add a client to an existing
|
||||||
This will be added post-MVP.
|
anonymous session" is planned but not yet implemented.
|
||||||
|
|
||||||
**Rationale:** The fundamental IRC mobile problem is that you can't have your
|
**Rationale:** The fundamental IRC mobile problem is that you can't have your
|
||||||
phone and laptop connected simultaneously without a bouncer. Server-side
|
phone and laptop connected simultaneously without a bouncer. Server-side
|
||||||
@@ -327,8 +358,8 @@ needs to revoke a token, change the expiry model, or add/remove claims, JWT
|
|||||||
clients may break or behave incorrectly.
|
clients may break or behave incorrectly.
|
||||||
|
|
||||||
Opaque tokens are simpler:
|
Opaque tokens are simpler:
|
||||||
- Server generates 32 random bytes → hex-encodes → stores hash
|
- Server generates 32 random bytes → hex-encodes → stores SHA-256 hash
|
||||||
- Client presents the token; server looks it up
|
- Client presents the raw token; server hashes and looks it up
|
||||||
- Revocation is a database delete
|
- Revocation is a database delete
|
||||||
- No clock skew issues, no algorithm confusion, no "none" algorithm attacks
|
- No clock skew issues, no algorithm confusion, no "none" algorithm attacks
|
||||||
- Token format can change without breaking clients
|
- Token format can change without breaking clients
|
||||||
@@ -355,6 +386,8 @@ The entire read/write loop for a client is two endpoints. Everything else
|
|||||||
|
|
||||||
### Session Lifecycle
|
### Session Lifecycle
|
||||||
|
|
||||||
|
#### Anonymous Session
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─ Client ──────────────────────────────────────────────────┐
|
┌─ Client ──────────────────────────────────────────────────┐
|
||||||
│ │
|
│ │
|
||||||
@@ -385,6 +418,29 @@ The entire read/write loop for a client is two endpoints. Everything else
|
|||||||
└────────────────────────────────────────────────────────────┘
|
└────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Registered Account
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─ Client ──────────────────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 1. POST /api/v1/register │
|
||||||
|
│ {"nick":"alice", "password":"s3cret!!"} │
|
||||||
|
│ → {"id":1, "nick":"alice", "token":"a1b2c3..."} │
|
||||||
|
│ (Session created with bcrypt-hashed password) │
|
||||||
|
│ │
|
||||||
|
│ ... use the API normally (JOIN, PRIVMSG, poll, etc.) ... │
|
||||||
|
│ │
|
||||||
|
│ (Later, from a new device or after token expiry) │
|
||||||
|
│ │
|
||||||
|
│ 2. POST /api/v1/login │
|
||||||
|
│ {"nick":"alice", "password":"s3cret!!"} │
|
||||||
|
│ → {"id":1, "nick":"alice", "token":"d4e5f6..."} │
|
||||||
|
│ (New client added to existing session — channels │
|
||||||
|
│ and message queues are preserved) │
|
||||||
|
│ │
|
||||||
|
└────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
### Queue Architecture
|
### Queue Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -1034,6 +1090,104 @@ TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/session \
|
|||||||
echo $TOKEN
|
echo $TOKEN
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### POST /api/v1/register — Register Account
|
||||||
|
|
||||||
|
Create a new user session with a password. The password is hashed with bcrypt
|
||||||
|
and stored server-side. The nick is claimed and can be reclaimed later via
|
||||||
|
`POST /api/v1/login`.
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{"nick": "alice", "password": "mypassword"}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Required | Constraints |
|
||||||
|
|------------|--------|----------|-------------|
|
||||||
|
| `nick` | string | Yes | 1–32 characters, must be unique on the server |
|
||||||
|
| `password` | string | Yes | Minimum 8 characters |
|
||||||
|
|
||||||
|
**Response:** `201 Created`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"nick": "alice",
|
||||||
|
"token": "494ba9fc0f2242873fc5c285dd4a24fc3844ba5e67789a17e69b6fe5f8c132e3"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| `id` | integer | Server-assigned user ID |
|
||||||
|
| `nick` | string | Confirmed nick |
|
||||||
|
| `token` | string | 64-character hex auth token |
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
|
||||||
|
| Status | Error | When |
|
||||||
|
|--------|-------|------|
|
||||||
|
| 400 | `invalid nick format` | Nick doesn't match allowed format |
|
||||||
|
| 400 | `password must be at least 8 characters` | Password too short |
|
||||||
|
| 409 | `nick already taken` | Another active session holds this nick |
|
||||||
|
|
||||||
|
**curl example:**
|
||||||
|
```bash
|
||||||
|
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/register \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"nick":"alice","password":"mypassword"}' | jq -r .token)
|
||||||
|
echo $TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /api/v1/login — Login to Account
|
||||||
|
|
||||||
|
Authenticate with a previously registered nick and password. Creates a new
|
||||||
|
client token for the existing session, preserving channel memberships and
|
||||||
|
message queues. This is how multi-client access works for registered accounts:
|
||||||
|
each login adds a new client to the session.
|
||||||
|
|
||||||
|
On successful login, the server enqueues MOTD messages and synthetic channel
|
||||||
|
state (JOIN + TOPIC + NAMES for each channel the session belongs to) into the
|
||||||
|
new client's queue, so the client can immediately restore its UI state.
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{"nick": "alice", "password": "mypassword"}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Required | Constraints |
|
||||||
|
|------------|--------|----------|-------------|
|
||||||
|
| `nick` | string | Yes | Must match a registered account |
|
||||||
|
| `password` | string | Yes | Must match the account's password |
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"nick": "alice",
|
||||||
|
"token": "7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| `id` | integer | Session ID (same as when registered) |
|
||||||
|
| `nick` | string | Current nick |
|
||||||
|
| `token` | string | New 64-character hex auth token for this client |
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
|
||||||
|
| Status | Error | When |
|
||||||
|
|--------|-------|------|
|
||||||
|
| 400 | `nick and password required` | Missing nick or password |
|
||||||
|
| 401 | `invalid credentials` | Wrong password, nick not found, or account has no password |
|
||||||
|
|
||||||
|
**curl example:**
|
||||||
|
```bash
|
||||||
|
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/login \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"nick":"alice","password":"mypassword"}' | jq -r .token)
|
||||||
|
echo $TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
### GET /api/v1/state — Get Session State
|
### GET /api/v1/state — Get Session State
|
||||||
|
|
||||||
Return the current user's session state.
|
Return the current user's session state.
|
||||||
@@ -1590,9 +1744,16 @@ authenticity.
|
|||||||
### Authentication
|
### Authentication
|
||||||
|
|
||||||
- **Session auth**: Opaque bearer tokens (64 hex chars = 256 bits of entropy).
|
- **Session auth**: Opaque bearer tokens (64 hex chars = 256 bits of entropy).
|
||||||
Tokens are stored in the database and validated on every request.
|
Tokens are hashed (SHA-256) before storage and validated on every request.
|
||||||
- **No passwords**: Session creation requires only a nick. The token is the
|
- **Anonymous sessions**: `POST /api/v1/session` requires only a nick. No
|
||||||
sole credential.
|
password, instant access. The token is the sole credential.
|
||||||
|
- **Registered accounts**: `POST /api/v1/register` accepts a nick and password
|
||||||
|
(minimum 8 characters). The password is hashed with bcrypt at the default
|
||||||
|
cost factor and stored alongside the session. `POST /api/v1/login`
|
||||||
|
authenticates against the stored hash and issues a new client token.
|
||||||
|
- **Password security**: Passwords are never stored in plain text. bcrypt
|
||||||
|
handles salting and key stretching automatically. Anonymous sessions have
|
||||||
|
an empty `password_hash` and cannot be logged into via `/login`.
|
||||||
- **Token security**: Tokens should be treated like session cookies. Transmit
|
- **Token security**: Tokens should be treated like session cookies. Transmit
|
||||||
only over HTTPS in production. If a token is compromised, the attacker has
|
only over HTTPS in production. If a token is compromised, the attacker has
|
||||||
full access to the session until QUIT or expiry.
|
full access to the session until QUIT or expiry.
|
||||||
@@ -1740,13 +1901,26 @@ The database schema is managed via embedded SQL migration files in
|
|||||||
|
|
||||||
**Current tables:**
|
**Current tables:**
|
||||||
|
|
||||||
#### `users`
|
#### `sessions`
|
||||||
|
| Column | Type | Description |
|
||||||
|
|----------------|----------|-------------|
|
||||||
|
| `id` | INTEGER | Primary key (auto-increment) |
|
||||||
|
| `uuid` | TEXT | Unique session UUID |
|
||||||
|
| `nick` | TEXT | Unique nick |
|
||||||
|
| `password_hash`| TEXT | bcrypt hash (empty string for anonymous sessions) |
|
||||||
|
| `signing_key` | TEXT | Public signing key (empty string if unset) |
|
||||||
|
| `away_message` | TEXT | Away message (empty string if not away) |
|
||||||
|
| `created_at` | DATETIME | Session creation time |
|
||||||
|
| `last_seen` | DATETIME | Last API request time |
|
||||||
|
|
||||||
|
#### `clients`
|
||||||
| Column | Type | Description |
|
| Column | Type | Description |
|
||||||
|-------------|----------|-------------|
|
|-------------|----------|-------------|
|
||||||
| `id` | INTEGER | Primary key (auto-increment) |
|
| `id` | INTEGER | Primary key (auto-increment) |
|
||||||
| `nick` | TEXT | Unique nick |
|
| `uuid` | TEXT | Unique client UUID |
|
||||||
| `token` | TEXT | Unique auth token (64 hex chars) |
|
| `session_id`| INTEGER | FK → sessions.id (cascade delete) |
|
||||||
| `created_at`| DATETIME | Session creation time |
|
| `token` | TEXT | Unique auth token (SHA-256 hash of 64 hex chars) |
|
||||||
|
| `created_at`| DATETIME | Client creation time |
|
||||||
| `last_seen` | DATETIME | Last API request time |
|
| `last_seen` | DATETIME | Last API request time |
|
||||||
|
|
||||||
#### `channels`
|
#### `channels`
|
||||||
@@ -1803,10 +1977,14 @@ skew issues) and simpler than UUIDs (integer comparison vs. string comparison).
|
|||||||
- **Client output queue entries**: Pruned automatically when older than
|
- **Client output queue entries**: Pruned automatically when older than
|
||||||
`QUEUE_MAX_AGE` (default 30 days).
|
`QUEUE_MAX_AGE` (default 30 days).
|
||||||
- **Channels**: Deleted when the last member leaves (ephemeral).
|
- **Channels**: Deleted when the last member leaves (ephemeral).
|
||||||
- **Users/sessions**: Deleted on `QUIT` or `POST /api/v1/logout`. Idle
|
- **Sessions**: Anonymous sessions are deleted on `QUIT` or when all clients
|
||||||
sessions are automatically expired after `SESSION_IDLE_TIMEOUT` (default
|
have logged out. Registered sessions persist across logouts — the session
|
||||||
30 days) — the server runs a background cleanup loop that parts idle users
|
remains so the user can log in again later. Idle sessions (both anonymous
|
||||||
from all channels, broadcasts QUIT, and releases their nicks.
|
and registered) are automatically expired after `SESSION_IDLE_TIMEOUT`
|
||||||
|
(default 30 days) — the server runs a background cleanup loop that parts
|
||||||
|
idle users from all channels, broadcasts QUIT, and releases their nicks.
|
||||||
|
- **Clients**: Individual client tokens are deleted on `POST /api/v1/logout`.
|
||||||
|
A session can have multiple clients; removing one doesn't affect others.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1955,11 +2133,21 @@ A complete client needs only four HTTP calls:
|
|||||||
### Step-by-Step with curl
|
### Step-by-Step with curl
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Create a session
|
# 1a. Create an anonymous session (no account)
|
||||||
export TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/session \
|
export TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/session \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{"nick":"testuser"}' | jq -r .token)
|
-d '{"nick":"testuser"}' | jq -r .token)
|
||||||
|
|
||||||
|
# 1b. Or register an account (persistent identity)
|
||||||
|
export TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/register \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"nick":"testuser","password":"mypassword"}' | jq -r .token)
|
||||||
|
|
||||||
|
# 1c. Or login to an existing account
|
||||||
|
export TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/login \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"nick":"testuser","password":"mypassword"}' | jq -r .token)
|
||||||
|
|
||||||
# 2. Join a channel
|
# 2. Join a channel
|
||||||
curl -s -X POST http://localhost:8080/api/v1/messages \
|
curl -s -X POST http://localhost:8080/api/v1/messages \
|
||||||
-H "Authorization: Bearer $TOKEN" \
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
@@ -2092,9 +2280,11 @@ Clients should handle these message commands from the queue:
|
|||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
- **HTTP 401**: Token expired or invalid. Re-create session.
|
- **HTTP 401**: Token expired or invalid. Re-create session (anonymous) or
|
||||||
|
re-login (registered account).
|
||||||
- **HTTP 404**: Channel or user not found.
|
- **HTTP 404**: Channel or user not found.
|
||||||
- **HTTP 409**: Nick already taken (on session creation or NICK change).
|
- **HTTP 409**: Nick already taken (on session creation, registration, or
|
||||||
|
NICK change).
|
||||||
- **HTTP 400**: Malformed request. Check the `error` field in the response.
|
- **HTTP 400**: Malformed request. Check the `error` field in the response.
|
||||||
- **Network errors**: Back off exponentially (1s, 2s, 4s, ..., max 30s).
|
- **Network errors**: Back off exponentially (1s, 2s, 4s, ..., max 30s).
|
||||||
|
|
||||||
@@ -2111,8 +2301,10 @@ Clients should handle these message commands from the queue:
|
|||||||
4. **DM tab logic**: When you receive a PRIVMSG where `to` is not a channel
|
4. **DM tab logic**: When you receive a PRIVMSG where `to` is not a channel
|
||||||
(no `#` prefix), the DM tab should be keyed by the **other** user's nick:
|
(no `#` prefix), the DM tab should be keyed by the **other** user's nick:
|
||||||
if `from` is you, use `to`; if `from` is someone else, use `from`.
|
if `from` is you, use `to`; if `from` is someone else, use `from`.
|
||||||
5. **Reconnection**: If the poll loop fails with 401, the session is gone.
|
5. **Reconnection**: If the poll loop fails with 401, the token is invalid.
|
||||||
Create a new session. If it fails with a network error, retry with backoff.
|
For anonymous sessions, create a new session. For registered accounts,
|
||||||
|
log in again via `POST /api/v1/login` to get a fresh token on the same
|
||||||
|
session. If it fails with a network error, retry with backoff.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -2383,9 +2575,12 @@ neoirc/
|
|||||||
build a working IRC-style TUI client against this API in an afternoon, the
|
build a working IRC-style TUI client against this API in an afternoon, the
|
||||||
API is too complex.
|
API is too complex.
|
||||||
|
|
||||||
2. **No accounts** — identity is a signing key, nick is a display name. No
|
2. **Accounts optional** — anonymous sessions are instant: pick a nick and
|
||||||
registration, no passwords, no email verification. Session creation is
|
talk. No registration, no email verification. The cost of entry is a
|
||||||
instant. The cost of entry is a hashcash proof, not bureaucracy.
|
hashcash proof, not bureaucracy. For users who want persistent identity,
|
||||||
|
optional account registration with password is available — but never
|
||||||
|
required. Identity verification at the message layer uses cryptographic
|
||||||
|
signing, independent of account status.
|
||||||
|
|
||||||
3. **IRC semantics over HTTP** — command names and numeric codes from
|
3. **IRC semantics over HTTP** — command names and numeric codes from
|
||||||
RFC 1459/2812. If you've built an IRC client or bot, you already know the
|
RFC 1459/2812. If you've built an IRC client or bot, you already know the
|
||||||
|
|||||||
Reference in New Issue
Block a user