Roles: add a system admin and lock down the user and API-key endpoints #3

Closed
opened 2026-09-20 05:58:43 +00:00 by niklas · 0 comments
Owner

Part of #1. Depends on the Postgres move.

Today

There are no roles. Every authenticated caller can create and delete users, set anyone's password and mint API keys — internal/api/users.go and auth.go say so in a comment ("open to any authenticated caller"). The only gate is AuthMiddleware (internal/api/middleware.go), which accepts a session cookie or a Bearer API key.

Scope

  • Add is_admin (or a role column) to users, with a migration.
  • POST /api/bootstrap creates the first user as an admin.
  • An AdminOnly middleware, alongside the existing AuthMiddleware.
  • Gate behind it: create user, delete user, set another user's password, grant or revoke admin, and minting API keys.
  • Leave self-service alone: a user still changes their own password and their own ntfy topic.
  • The last admin cannot be deleted or demoted.
  • The web UI hides admin-only actions for non-admins, and the API enforces it regardless.
  • Tests: a non-admin gets 403 on each gated endpoint.

Notes

Team roles (owner/member) are a separate thing and arrive with teams. This issue is only the system-wide admin.

Done when

A non-admin user cannot create users or API keys through the API, the existing admin keeps working, and the migration marks the current users appropriately (probably all of them, since everyone has these powers today — decide explicitly).

Part of #1. Depends on the Postgres move. ### Today There are no roles. Every authenticated caller can create and delete users, set anyone's password and mint API keys — `internal/api/users.go` and `auth.go` say so in a comment ("open to any authenticated caller"). The only gate is `AuthMiddleware` (`internal/api/middleware.go`), which accepts a session cookie or a Bearer API key. ### Scope - [ ] Add `is_admin` (or a role column) to `users`, with a migration. - [ ] `POST /api/bootstrap` creates the first user as an admin. - [ ] An `AdminOnly` middleware, alongside the existing `AuthMiddleware`. - [ ] Gate behind it: create user, delete user, set another user's password, grant or revoke admin, and minting API keys. - [ ] Leave self-service alone: a user still changes their own password and their own ntfy topic. - [ ] The last admin cannot be deleted or demoted. - [ ] The web UI hides admin-only actions for non-admins, and the API enforces it regardless. - [ ] Tests: a non-admin gets 403 on each gated endpoint. ### Notes Team roles (`owner`/`member`) are a separate thing and arrive with teams. This issue is only the system-wide admin. ### Done when A non-admin user cannot create users or API keys through the API, the existing admin keeps working, and the migration marks the current users appropriately (probably all of them, since everyone has these powers today — decide explicitly).
niklas added the auth label 2026-09-20 06:13:00 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: niklas/terdut-server#3