feat(auth): add DB-backed login, token management, and idempotent auth migration
This commit is contained in:
@@ -72,10 +72,15 @@ Configuration precedence (high to low):
|
||||
Core settings:
|
||||
|
||||
- `PORTFOLIOHUB_ALLOWED_ORIGINS`: comma-separated CORS origins
|
||||
- `PORTFOLIOHUB_BOOTSTRAP_USERNAME`: initial username created on startup when users table is empty
|
||||
- `PORTFOLIOHUB_BOOTSTRAP_EMAIL`: optional email for the bootstrap user
|
||||
- `PORTFOLIOHUB_BOOTSTRAP_PASSWORD`: initial password for the bootstrap admin user
|
||||
- `PORTFOLIOHUB_READ_TOKENS`: comma-separated read tokens
|
||||
- `PORTFOLIOHUB_TRADE_WRITE_TOKENS`: comma-separated write tokens
|
||||
- `PORTFOLIOHUB_ADMIN_TOKENS`: comma-separated admin tokens
|
||||
- `PORTFOLIOHUB_DB_ENABLED`: enables DB repository selection when `true`
|
||||
- `PORTFOLIOHUB_SESSION_TOKEN_TTL_HOURS`: login session token TTL in hours
|
||||
- `PORTFOLIOHUB_CLIENT_TOKEN_DEFAULT_TTL_DAYS`: default client token TTL in days
|
||||
|
||||
Database settings (active source):
|
||||
|
||||
@@ -121,6 +126,7 @@ Failure responses:
|
||||
Base routes:
|
||||
|
||||
- Health: `/health`
|
||||
- Auth: `/auth`
|
||||
- Portfolio: `/portfolios`
|
||||
- Users: `/users`
|
||||
|
||||
@@ -247,7 +253,38 @@ Note: Since strategy sets are identified by (name, config) uniqueness, updating
|
||||
|
||||
- See `docs/api-examples.md` for maintained request/response examples.
|
||||
|
||||
### 7.5 User Endpoints
|
||||
### 7.5 Auth Endpoints
|
||||
|
||||
#### Login
|
||||
|
||||
- `POST /auth/login`
|
||||
- Auth: none
|
||||
- Body: `LoginRequest`
|
||||
- Response `200`: `TokenResponse`
|
||||
- Response `401`: invalid username/password
|
||||
|
||||
#### List Current Tokens
|
||||
|
||||
- `GET /auth/tokens`
|
||||
- Auth: `read` or higher with DB-issued token/session
|
||||
- Response `200`: array of `AuthTokenResponse`
|
||||
|
||||
#### Create Client Token
|
||||
|
||||
- `POST /auth/tokens`
|
||||
- Auth: `read` or higher with DB-issued token/session
|
||||
- Body: `CreateClientTokenRequest`
|
||||
- Response `201`: `IssuedClientTokenResponse`
|
||||
- Response `403`: requested token permission exceeds current permission
|
||||
|
||||
#### Revoke Client Token
|
||||
|
||||
- `DELETE /auth/tokens/{token_id}`
|
||||
- Auth: `read` or higher with DB-issued token/session
|
||||
- Response `204`: no content
|
||||
- Response `404`: token not found
|
||||
|
||||
### 7.6 User Endpoints
|
||||
|
||||
All user management endpoints are admin-only.
|
||||
|
||||
@@ -272,6 +309,10 @@ All user management endpoints are admin-only.
|
||||
- Response `201`: `UserResponse`
|
||||
- Response `409`: duplicate username or email
|
||||
|
||||
Bootstrap rule:
|
||||
|
||||
- If DB-backed persistence is enabled and both `PORTFOLIOHUB_BOOTSTRAP_USERNAME` and `PORTFOLIOHUB_BOOTSTRAP_PASSWORD` are configured, application startup creates the bootstrap admin user only when the `users` table is empty.
|
||||
|
||||
#### Update User
|
||||
|
||||
- `PATCH /users/{user_id}`
|
||||
@@ -326,11 +367,28 @@ All user management endpoints are admin-only.
|
||||
|
||||
- `username: str`
|
||||
- `email: str | null`
|
||||
- `password: str`
|
||||
- `permission: "read" | "trade-write" | "admin"`
|
||||
- `is_active: bool`
|
||||
|
||||
`UpdateUserRequest`
|
||||
|
||||
- `username: str | null`
|
||||
- `email: str | null`
|
||||
- `password: str | null`
|
||||
- `permission: "read" | "trade-write" | "admin" | null`
|
||||
- `is_active: bool | null`
|
||||
|
||||
`LoginRequest`
|
||||
|
||||
- `username: str`
|
||||
- `password: str`
|
||||
|
||||
`CreateClientTokenRequest`
|
||||
|
||||
- `name: str`
|
||||
- `permission: "read" | "trade-write" | "admin" | null`
|
||||
- `expires_in_days: int | null`
|
||||
- `price: float > 0`
|
||||
- `fee: float >= 0`
|
||||
- `tax: float >= 0`
|
||||
|
||||
Reference in New Issue
Block a user