Documentation cleanup for public release (#38)
* docs: cleanup for public release (fix stale/wrong API docs, LICENSE, versions)
Documentation cleanup ahead of the public release announcement. Fixes a set
of confirmed issues from a prior audit:
- LICENSE: fill in MIT template placeholders (theta42, 2026).
- README.md: fix broken API docs link (api.md -> API.md), correct required
Node.js version (13.x -> 20.x), add the missing app_sso_invite group to
the LDAP groups table, scrub hardcoded dc=theta42,dc=com to the generic
dc=example,dc=com used elsewhere, add a "Recommended: Docker or
install.sh" section pointing to DEPLOYMENT.md/docs before the manual
OpenLDAP walkthrough, and drop an emoji from a warning callout.
- nodejs/api.md: deleted — it was a stale/legacy doc with wrong routes,
wrong request bodies, and endpoints that are dead/commented-out code.
The root API.md is the accurate, current reference; README now links
there directly.
- API.md: add the missing app_sso_invite permission group, fix the
documented invite response to match the real {token, link, mail_sent}
payload, document the previously-undocumented GET/PUT/DELETE
/api/user/invite endpoints, add the real allowed_groups field to the
OAuth client management examples, and document POST /api/oauth/authorize
(the endpoint that actually issues the code after consent).
- nodejs/routes/auth.js + API.md: fix "emaill address" typo in the
password-reset response message (source and docs kept in sync).
- DEPLOYMENT.md: fix the top-level summary to mention Redis, matching
docs/deployment.md and the entrypoint behavior it already documents.
Flagged, not changed: tos.md reads like a personal home-lab acceptable-use
policy (Emby/Gitea/Proxmox/Discord/Signal, first-person "the admin") rather
than generic OSS docs. Left in place pending a manual decision to
genericize, relocate, or remove it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: genericize tos.md template, track runtime-editable terms in #39
Removes operator-specific references (Emby, Gitea, Proxmox, Discord,
Signal, first-person "the admin") so the shipped tos.md reads as a
neutral starting template rather than one operator's internal policy.
Actual runtime editability (admin/legal editing terms without a code
change) is tracked in issue #39, not implemented here.
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,7 @@ auth-token: <token>
|
||||
|-------|--------|
|
||||
| `app_sso_admin` | Full user/group/notification management |
|
||||
| `app_sso_oauth_admin` | Register and manage OAuth clients |
|
||||
| `app_sso_invite` | Invitation management |
|
||||
| Group owner | Manage membership of that specific group |
|
||||
|
||||
Self-service: users can always read and modify their own account without admin membership.
|
||||
@@ -116,7 +117,7 @@ Returns available username suggestions based on name and optional date of birth.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "message": "If the emaill address is in our system, you will receive a message." }
|
||||
{ "message": "If the email address is in our system, you will receive a message." }
|
||||
```
|
||||
|
||||
The same response is returned whether or not the email exists. Reset tokens expire after 24 hours.
|
||||
@@ -506,11 +507,90 @@ When an admin changes another user's password, `password_must_change` is set on
|
||||
|
||||
### Generate Invite Token
|
||||
|
||||
**`POST /api/user/invite`** — Any authenticated user
|
||||
Create an invite token, optionally emailing it to the invitee and pre-assigning
|
||||
LDAP groups the new account should be added to on signup.
|
||||
|
||||
**`POST /api/user/invite`** — `app_sso_admin` or `app_sso_invite` required
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{ "mail": "invitee@example.com", "groups": ["group_name"] }
|
||||
```
|
||||
|
||||
`mail` and `groups` are both optional. If `mail` is provided, a verification
|
||||
email is sent to that address.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "token": "invite_token_string" }
|
||||
{
|
||||
"token": "invite_token_string",
|
||||
"link": "https://your-domain.com/login/invite/invite_token_string",
|
||||
"mail_sent": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### List Invite Tokens
|
||||
|
||||
**`GET /api/user/invite`** — `app_sso_admin` or `app_sso_invite` required
|
||||
|
||||
Admins (`app_sso_admin`) see all invite tokens; non-admin `app_sso_invite`
|
||||
members see only invites they created.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"token": "invite_token_string",
|
||||
"created_by": "username",
|
||||
"created_on": 1234567890000,
|
||||
"is_valid": true,
|
||||
"mail": "invitee@example.com",
|
||||
"groups": "[\"group_name\"]"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Invite Token
|
||||
|
||||
Update the groups an invite will assign, or change/clear the invitee's email
|
||||
(re-sends verification if a new email is set).
|
||||
|
||||
**`PUT /api/user/invite/:token`** — `app_sso_admin`, or the `app_sso_invite`
|
||||
member who created the invite
|
||||
|
||||
**URL Parameters:** `token` — invite token
|
||||
|
||||
**Request:** Any subset of:
|
||||
```json
|
||||
{ "groups": ["group_name"], "mail": "newinvitee@example.com" }
|
||||
```
|
||||
|
||||
Set `mail` to `null`/empty to clear it. Fails with `400` if the token is no
|
||||
longer valid.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "results": { "token": "invite_token_string", "is_valid": true, "...": "..." } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Revoke Invite Token
|
||||
|
||||
**`DELETE /api/user/invite/:token`** — `app_sso_admin`, or the `app_sso_invite`
|
||||
member who created the invite
|
||||
|
||||
**URL Parameters:** `token` — invite token
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "results": true }
|
||||
```
|
||||
|
||||
---
|
||||
@@ -831,7 +911,44 @@ Returns the OIDC discovery document with endpoint URLs, supported scopes, and si
|
||||
- `code_challenge` — PKCE challenge (SHA-256 of code_verifier, base64url-encoded)
|
||||
- `code_challenge_method` — Must be `S256`
|
||||
|
||||
Renders the consent screen. On approval, redirects to `redirect_uri?code=<code>&state=<state>`.
|
||||
Renders the consent screen.
|
||||
|
||||
---
|
||||
|
||||
### Authorize (Issue Code)
|
||||
|
||||
Issues the authorization code after the user approves the consent form shown
|
||||
by the Authorization Endpoint above. This is called by the consent page itself
|
||||
(an authenticated request, via `auth-token`), not by the OAuth client
|
||||
directly.
|
||||
|
||||
**`POST /api/oauth/authorize`** — Auth required (`auth-token` header)
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"response_type": "code",
|
||||
"client_id": "uuid",
|
||||
"redirect_uri": "https://ha.example.com/auth/external/callback",
|
||||
"scope": "openid profile email",
|
||||
"state": "opaque-state-value",
|
||||
"code_challenge": "pkce-challenge",
|
||||
"code_challenge_method": "S256"
|
||||
}
|
||||
```
|
||||
|
||||
Only scopes the client is actually registered for are granted, even if more
|
||||
are requested. If the client has `allowed_groups` set, the authenticated user
|
||||
must be a member of at least one of those groups or the request is rejected
|
||||
with `403`.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{ "redirect_url": "https://ha.example.com/auth/external/callback?code=<code>&state=<state>" }
|
||||
```
|
||||
|
||||
The caller (the consent page) redirects the browser to `redirect_url`, which
|
||||
completes the flow described in the Authorization Endpoint section above.
|
||||
|
||||
---
|
||||
|
||||
@@ -916,6 +1033,7 @@ All endpoints require authentication and `app_sso_oauth_admin` membership.
|
||||
"description": "Home automation",
|
||||
"redirect_uris": ["https://ha.example.com/auth/external/callback"],
|
||||
"scopes": ["openid", "profile", "email"],
|
||||
"allowed_groups": [],
|
||||
"token_lifetime": { "access_token": 3600, "refresh_token": 2592000 },
|
||||
"created_by": "wmantly",
|
||||
"created_on": 1234567890000
|
||||
@@ -937,11 +1055,13 @@ All endpoints require authentication and `app_sso_oauth_admin` membership.
|
||||
"description": "Home automation dashboard",
|
||||
"redirect_uris": ["https://ha.example.com/auth/external/callback"],
|
||||
"scopes": ["openid", "profile", "email"],
|
||||
"allowed_groups": [],
|
||||
"token_lifetime": { "access_token": 3600, "refresh_token": 2592000 }
|
||||
}
|
||||
```
|
||||
|
||||
`redirect_uris` may also be a newline-separated string. `scopes` may also be a space-separated string.
|
||||
`allowed_groups` restricts the client to members of the listed SSO groups (empty/omitted = any valid user).
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
@@ -968,7 +1088,7 @@ The `client_secret` is shown **only once**. Store it immediately.
|
||||
|
||||
**`PUT /api/oauth/client/:client_id`**
|
||||
|
||||
**Request:** Any subset of `name`, `description`, `redirect_uris`, `scopes`, `token_lifetime`, `is_valid`.
|
||||
**Request:** Any subset of `name`, `description`, `redirect_uris`, `scopes`, `allowed_groups`, `token_lifetime`, `is_valid`.
|
||||
|
||||
**Response:** `{ "results": { <updated client> }, "message": "..." }`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user