diff options
| author | tv <tv@krebsco.de> | 2026-11-07 22:35:21 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-07 22:35:21 +0100 |
| commit | e696d2f40636a6613eddfb1a3afdf87aa7ffdedd (patch) | |
| tree | b2734381ef1d010d0efad209f116b12f625c0f40 /docs | |
| parent | 70ff0ec9e50bf506cc6d80b929a81e350289f6cc (diff) | |
auth: logging in by key
POST /auth/challenge and /auth/login/key: a node-signed challenge,
valid five minutes and taken once, signed with one of the user's SSH
keys (ssh-keygen -Y sign -n continuum-login), for a token.
Auth plan M7 (key login, M2b).
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/access.md | 16 | ||||
| -rw-r--r-- | docs/openapi.yaml | 57 |
2 files changed, 73 insertions, 0 deletions
diff --git a/docs/access.md b/docs/access.md index 20fa23d..a182266 100644 --- a/docs/access.md +++ b/docs/access.md @@ -106,6 +106,22 @@ curl -H "Authorization: Bearer ct1.…" http://other-node:3000/store write anything as anyone ([`trust.md`](trust.md)). A token is a bearer's: whoever holds it is the user until it ends, so it goes over TLS only, as passwords do. +A user with keys in its entry (`keys`, The registry, above) logs in on any node without +a password: it asks for a challenge, signs it with one of its keys, and gets the same +token (`login: "key"`). + +```sh +c=$(curl -s -X POST localhost:3000/auth/challenge | jq -r .challenge) +printf %s "$c" | ssh-keygen -Y sign -f ~/.ssh/id_ed25519 -n continuum-login > sig +jq -n --arg c "$c" --rawfile s sig '{user: "alice", challenge: $c, signature: $s}' | + curl -s -X POST localhost:3000/auth/login/key -H 'Content-Type: application/json' -d @- +``` + +A challenge is the node's, signed by it, valid for five minutes, and taken once; +the signature must be by one of the user's keys, as the registry the node holds then +says, and the user enabled (`401` if not, saying why). A swarm without a registry has +no keys (`409`). + `GET /auth/whoami` says who a request's user is, how it proved it, and what it may do. Pages of other origins, the dashboards of other members, may call a node with a token: diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 6abfc6d..1bd3a16 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -838,6 +838,63 @@ paths: '403': { description: Not a registered, enabled user. } '503': { description: Not ready yet. } + /auth/challenge: + post: + tags: [Auth] + summary: A challenge to log in by key + description: | + A challenge for `POST /auth/login/key`, signed by this node, valid for five + minutes, taken once. The user signs it, exactly, with one of its keys + (`docs/access.md`, The registry), as `ssh-keygen -Y sign -n continuum-login` + does. No authentication. + security: [] + responses: + '200': + description: The challenge. + content: + application/json: + schema: + type: object + properties: + challenge: { type: string, example: 'cc1.eyJub2RlIjo….Tm9kZS…' } + namespace: { type: string, example: continuum-login } + expiresAt: { type: integer, format: int64, description: Unix ms. } + '503': { description: Not ready yet. } + + /auth/login/key: + post: + tags: [Auth] + summary: Log in by key for a token + description: | + A challenge (`POST /auth/challenge`) signed by one of the user's keys: a token, + as `POST /auth/login` gives one (`login: key`). No authentication: the + signature proves the user. + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [user, challenge, signature] + properties: + user: { type: string } + challenge: { type: string } + signature: { type: string, description: 'Armored, as `ssh-keygen -Y sign` writes it.' } + limit: + type: array + items: { $ref: '#/components/schemas/CapabilityRequest' } + responses: + '200': + description: The token. + content: + application/json: + schema: { $ref: '#/components/schemas/TokenAnswer' } + '400': { description: A request or limit that isn't one. } + '401': { description: 'Not a challenge of this node, expired or used, or not signed by one of the user''s keys, or the user disabled or unknown (the message says which).' } + '409': { description: No user registry, which holds the keys. } + '503': { description: Not ready yet. } + /auth/refresh: post: tags: [Auth] |
