825 lines
18 KiB
Markdown
825 lines
18 KiB
Markdown
# Auth Service API Documentation
|
|
|
|
**Base URL:** `/api/auth` (via gateway) or `http://localhost:8082` (direct)
|
|
|
|
**Service Port:** 8082
|
|
|
|
## Overview
|
|
|
|
The Auth Service handles all authentication and authorization for the Coppertone.tech platform. It supports:
|
|
|
|
- Multi-factor authentication (email/password + blockchain identity)
|
|
- Role-based access control (RBAC)
|
|
- Superuser hierarchy with protected initial superuser
|
|
- Identity linking/unlinking
|
|
|
|
## Role Hierarchy
|
|
|
|
| Role | Level | Description |
|
|
|------|-------|-------------|
|
|
| `SUPERUSER` | Highest | God-like permissions, full system access |
|
|
| `ADMIN` | High | Can manage STAFF/CLIENT, cannot touch SUPERUSERs |
|
|
| `STAFF` | Medium | Internal staff, can manage work orders |
|
|
| `CLIENT` | Low | External clients, limited to own resources |
|
|
|
|
### Special Flags
|
|
|
|
- **`is_initial_superuser`**: Marks the founding superuser. Cannot be deleted or demoted. Can only transfer status.
|
|
- **`is_protected`**: Protected users cannot be deleted from the system.
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
All protected endpoints require a JWT token in the Authorization header:
|
|
|
|
```
|
|
Authorization: Bearer <jwt_token>
|
|
```
|
|
|
|
### JWT Token Claims
|
|
|
|
```json
|
|
{
|
|
"user_id": 1,
|
|
"userId": 1,
|
|
"email": "user@example.com",
|
|
"roles": ["CLIENT", "ADMIN"],
|
|
"isInitialSuperuser": false,
|
|
"exp": 1699999999
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Public Endpoints
|
|
|
|
### Health Check
|
|
|
|
Check if the service is running.
|
|
|
|
```
|
|
GET /healthz
|
|
```
|
|
|
|
**Response:**
|
|
```
|
|
200 OK
|
|
ok
|
|
```
|
|
|
|
---
|
|
|
|
## Registration Endpoints
|
|
|
|
### Register with Email/Password
|
|
|
|
Create a new user account using email and password authentication.
|
|
|
|
```
|
|
POST /register-email-password
|
|
```
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "SecurePass123",
|
|
"name": "John Doe"
|
|
}
|
|
```
|
|
|
|
**Validation Rules:**
|
|
| Field | Rules |
|
|
|-------|-------|
|
|
| `email` | Required, valid email format, max 254 characters |
|
|
| `password` | Required, 8-72 characters, must contain uppercase, lowercase, and number |
|
|
| `name` | Required, max 100 characters |
|
|
|
|
**Response (201 Created):**
|
|
```json
|
|
{
|
|
"message": "User registered successfully",
|
|
"userId": 1
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Validation error | `{"field": "email", "message": "Invalid email format"}` |
|
|
| 409 | Email exists | `Email already registered` |
|
|
| 500 | Server error | `Failed to create user` |
|
|
|
|
**Special Behavior:**
|
|
- First user registered automatically becomes `SUPERUSER` with `is_initial_superuser = true`
|
|
- All subsequent users are assigned `CLIENT` role
|
|
- Role cannot be specified during registration (security measure)
|
|
|
|
---
|
|
|
|
### Register with Blockchain Address
|
|
|
|
Create a new user account using Ethereum blockchain identity.
|
|
|
|
```
|
|
POST /register-blockchain
|
|
```
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1b2b1",
|
|
"signature": "0x...",
|
|
"message": "Sign this message to register: <timestamp>",
|
|
"name": "John Doe"
|
|
}
|
|
```
|
|
|
|
**Validation Rules:**
|
|
| Field | Rules |
|
|
|-------|-------|
|
|
| `address` | Required, valid Ethereum address (0x + 40 hex chars) |
|
|
| `signature` | Required, valid Ethereum signature (65 bytes) |
|
|
| `message` | Required, message that was signed |
|
|
| `name` | Required, max 100 characters |
|
|
|
|
**Signature Verification:**
|
|
- Uses Ethereum personal_sign format
|
|
- Message is prefixed with `\x19Ethereum Signed Message:\n<length>`
|
|
- Public key is recovered and compared to provided address
|
|
|
|
**Response (201 Created):**
|
|
```json
|
|
{
|
|
"message": "User registered successfully",
|
|
"userId": 1
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Missing fields | `Blockchain address is required` |
|
|
| 401 | Invalid signature | `Invalid signature` |
|
|
| 409 | Address exists | `Blockchain address already registered` |
|
|
| 500 | Server error | `Failed to create user` |
|
|
|
|
---
|
|
|
|
## Login Endpoints
|
|
|
|
### Login with Email/Password
|
|
|
|
Authenticate using email and password credentials.
|
|
|
|
```
|
|
POST /login-email-password
|
|
```
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "SecurePass123"
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Invalid JSON | Error message |
|
|
| 401 | Wrong credentials | `Invalid credentials` |
|
|
| 500 | Server error | `Login failed` |
|
|
|
|
**Token Expiry:** 24 hours
|
|
|
|
---
|
|
|
|
### Login with Blockchain Signature
|
|
|
|
Authenticate using Ethereum wallet signature.
|
|
|
|
```
|
|
POST /login-blockchain
|
|
```
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1b2b1",
|
|
"signature": "0x...",
|
|
"message": "Sign this message to login: <timestamp>"
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 401 | Invalid signature | `Invalid signature` |
|
|
| 401 | Not registered | `Address not registered` |
|
|
| 500 | Server error | `Login failed` |
|
|
|
|
---
|
|
|
|
## Protected Endpoints
|
|
|
|
### Get User Profile
|
|
|
|
Retrieve the authenticated user's profile.
|
|
|
|
```
|
|
GET /profile
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** Any authenticated user
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"name": "John Doe",
|
|
"email": "user@example.com",
|
|
"roles": ["CLIENT"],
|
|
"isInitialSuperuser": false,
|
|
"isProtected": false,
|
|
"createdAt": "2024-01-15T10:30:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Identity Management
|
|
|
|
### Get User Identities
|
|
|
|
List all authentication identities linked to the current user.
|
|
|
|
```
|
|
GET /identities
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** Any authenticated user
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"userId": 1,
|
|
"type": "email_password",
|
|
"identifier": "user@example.com",
|
|
"isPrimaryLogin": true,
|
|
"createdAt": "2024-01-15T10:30:00Z"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"userId": 1,
|
|
"type": "blockchain_address",
|
|
"identifier": "0x742d35cc6634c0532925a3b844bc9e7595f1b2b1",
|
|
"isPrimaryLogin": false,
|
|
"createdAt": "2024-01-16T14:20:00Z"
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### Link New Identity
|
|
|
|
Add a new authentication method to the current user's account.
|
|
|
|
```
|
|
POST /link-identity
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `CLIENT`, `STAFF`, or `ADMIN`
|
|
|
|
**Request Body (Email/Password):**
|
|
```json
|
|
{
|
|
"type": "email_password",
|
|
"email": "alternate@example.com",
|
|
"password": "SecurePass123"
|
|
}
|
|
```
|
|
|
|
**Request Body (Blockchain):**
|
|
```json
|
|
{
|
|
"type": "blockchain_address",
|
|
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1b2b1",
|
|
"signature": "0x...",
|
|
"message": "Link this wallet to my account: <timestamp>"
|
|
}
|
|
```
|
|
|
|
**Response (201 Created):**
|
|
```json
|
|
{
|
|
"message": "Identity linked successfully"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Invalid type | `Invalid identity type` |
|
|
| 400 | Validation error | `{"field": "email", "message": "..."}` |
|
|
| 401 | Invalid signature | `Invalid signature` |
|
|
| 409 | Already linked | `Identity already linked` |
|
|
|
|
---
|
|
|
|
### Unlink Identity
|
|
|
|
Remove an authentication method from the current user's account.
|
|
|
|
```
|
|
POST /unlink-identity
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `CLIENT`, `STAFF`, or `ADMIN`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"identityId": 2
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Identity unlinked successfully"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Last identity | `Cannot remove your last identity. You must have at least one login method.` |
|
|
| 403 | Not owner | `Forbidden: identity does not belong to you` |
|
|
| 404 | Not found | `Identity not found` |
|
|
|
|
**Notes:**
|
|
- Cannot remove the last identity (must have at least one login method)
|
|
- If unlinking primary identity, another identity is automatically promoted to primary
|
|
|
|
---
|
|
|
|
## Admin Endpoints
|
|
|
|
### Get All Users
|
|
|
|
Retrieve a list of all users in the system.
|
|
|
|
```
|
|
GET /admin/users
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `ADMIN` or `SUPERUSER`
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"name": "Admin User",
|
|
"email": "admin@example.com",
|
|
"roles": ["SUPERUSER"],
|
|
"isInitialSuperuser": true,
|
|
"isProtected": true,
|
|
"createdAt": "2024-01-01T00:00:00Z"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "John Doe",
|
|
"email": "john@example.com",
|
|
"roles": ["CLIENT"],
|
|
"isInitialSuperuser": false,
|
|
"isProtected": false,
|
|
"createdAt": "2024-01-15T10:30:00Z"
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### Promote User Role
|
|
|
|
Grant a role to a user.
|
|
|
|
```
|
|
POST /admin/users/promote-role
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `ADMIN` or `SUPERUSER`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"userId": 2,
|
|
"role": "STAFF"
|
|
}
|
|
```
|
|
|
|
**Valid Roles:** `CLIENT`, `STAFF`, `ADMIN`
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Successfully granted STAFF role to user 2"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Invalid role | `Invalid role. Must be CLIENT, STAFF, or ADMIN` |
|
|
| 400 | SUPERUSER role | `Use /superuser/promote endpoint to promote to SUPERUSER` |
|
|
| 403 | ADMIN touching SUPERUSER | `Forbidden: ADMINs cannot modify SUPERUSER accounts` |
|
|
| 404 | User not found | `User not found` |
|
|
| 409 | Already has role | `User already has STAFF role` |
|
|
|
|
**Restrictions:**
|
|
- `ADMIN` users cannot promote users who have `SUPERUSER` role
|
|
- `SUPERUSER` promotion requires `/superuser/promote` endpoint
|
|
- Audit log entry is created for each promotion
|
|
|
|
---
|
|
|
|
### Demote User Role
|
|
|
|
Remove a role from a user.
|
|
|
|
```
|
|
POST /admin/users/demote-role
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `ADMIN` or `SUPERUSER`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"userId": 2,
|
|
"role": "ADMIN"
|
|
}
|
|
```
|
|
|
|
**Valid Roles:** `CLIENT`, `STAFF`, `ADMIN`
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Successfully removed ADMIN role from user 2"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Invalid role | `Invalid role. Must be CLIENT, STAFF, or ADMIN` |
|
|
| 400 | SUPERUSER role | `Use /superuser/demote endpoint to remove SUPERUSER role` |
|
|
| 400 | Only role | `Cannot remove user's only role. Assign a different role first.` |
|
|
| 403 | Self-demotion | `Cannot remove your own ADMIN role` |
|
|
| 403 | ADMIN touching SUPERUSER | `Forbidden: ADMINs cannot modify SUPERUSER accounts` |
|
|
| 404 | User not found | `User not found` |
|
|
| 404 | Doesn't have role | `User does not have ADMIN role` |
|
|
|
|
**Restrictions:**
|
|
- Cannot remove a user's only role
|
|
- `ADMIN` cannot demote themselves from `ADMIN` (unless they're also `SUPERUSER`)
|
|
- `ADMIN` users cannot demote users who have `SUPERUSER` role
|
|
- `SUPERUSER` demotion requires `/superuser/demote` endpoint
|
|
|
|
---
|
|
|
|
## Superuser Endpoints
|
|
|
|
### Promote to Superuser
|
|
|
|
Promote a user to SUPERUSER role.
|
|
|
|
```
|
|
POST /superuser/promote
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `SUPERUSER` only
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"userId": 3
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Successfully promoted user 3 to SUPERUSER"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 403 | Not SUPERUSER | `Forbidden: insufficient permissions` |
|
|
| 404 | User not found | `User not found` |
|
|
| 409 | Already SUPERUSER | `User is already a SUPERUSER` |
|
|
|
|
**Notes:**
|
|
- Only existing `SUPERUSER` users can promote others to `SUPERUSER`
|
|
- New `SUPERUSER` does not become `is_initial_superuser`
|
|
- Audit log entry is created
|
|
|
|
---
|
|
|
|
### Demote from Superuser
|
|
|
|
Remove SUPERUSER role from a user.
|
|
|
|
```
|
|
POST /superuser/demote
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `SUPERUSER` only
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"userId": 3
|
|
}
|
|
```
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Successfully removed SUPERUSER role from user 3"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 403 | Not SUPERUSER | `Forbidden: insufficient permissions` |
|
|
| 403 | Self-demotion | `Cannot demote yourself. Have another SUPERUSER do it.` |
|
|
| 403 | Initial SUPERUSER | `Cannot demote the INITIAL SUPERUSER. They must transfer their status first using /superuser/transfer` |
|
|
| 404 | User not found | `User not found` |
|
|
| 404 | Not a SUPERUSER | `User does not have SUPERUSER role` |
|
|
|
|
**Special Behavior:**
|
|
- Cannot demote the `is_initial_superuser` - they must transfer first
|
|
- Cannot demote yourself - another `SUPERUSER` must do it
|
|
- If user has no other roles, `CLIENT` role is automatically added before demotion
|
|
- Audit log entry is created
|
|
|
|
---
|
|
|
|
### Transfer Initial Superuser Status
|
|
|
|
Transfer the initial superuser status to another user. **Only the current initial superuser can call this endpoint.**
|
|
|
|
```
|
|
POST /superuser/transfer
|
|
```
|
|
|
|
**Headers:**
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Required Role:** `SUPERUSER` with `is_initial_superuser = true`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"newSuperuserId": 5,
|
|
"reason": "Retiring from the company, transferring ownership to new CTO"
|
|
}
|
|
```
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `newSuperuserId` | integer | Yes | User ID to receive initial superuser status |
|
|
| `reason` | string | No | Reason for transfer (stored in audit log) |
|
|
|
|
**Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Successfully transferred INITIAL SUPERUSER status to user 5 (Jane Smith)"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Condition | Response |
|
|
|--------|-----------|----------|
|
|
| 400 | Self-transfer | `Cannot transfer to yourself` |
|
|
| 403 | Not initial SUPERUSER | `Forbidden: Only the INITIAL SUPERUSER can transfer their status` |
|
|
| 404 | Target not found | `Target user not found` |
|
|
|
|
**What Happens During Transfer:**
|
|
1. `is_initial_superuser` flag removed from current user
|
|
2. `is_initial_superuser` and `is_protected` flags set on new user
|
|
3. New user automatically granted `SUPERUSER` role (if not already)
|
|
4. Transfer recorded in `superuser_transfers` audit table
|
|
5. Original user retains `SUPERUSER` role (can be demoted by new initial SUPERUSER)
|
|
|
|
**Audit Trail:**
|
|
```sql
|
|
SELECT * FROM superuser_transfers;
|
|
-- id | from_user_id | to_user_id | transferred_at | reason
|
|
-- 1 | 1 | 5 | 2024-01-20... | Retiring from company...
|
|
```
|
|
|
|
---
|
|
|
|
## Error Response Format
|
|
|
|
All error responses follow this format:
|
|
|
|
**Simple Error:**
|
|
```
|
|
HTTP/1.1 400 Bad Request
|
|
Content-Type: text/plain
|
|
|
|
Invalid request body
|
|
```
|
|
|
|
**Validation Error:**
|
|
```json
|
|
HTTP/1.1 400 Bad Request
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"field": "email",
|
|
"message": "Invalid email format"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## CORS Configuration
|
|
|
|
The service supports CORS with the following configuration:
|
|
|
|
| Header | Value |
|
|
|--------|-------|
|
|
| `Access-Control-Allow-Origin` | Configured via `CORS_ALLOW_ORIGIN` env var (default: `http://localhost:8090`) |
|
|
| `Access-Control-Allow-Methods` | `GET, POST, PUT, DELETE, OPTIONS` |
|
|
| `Access-Control-Allow-Headers` | `Content-Type, Authorization` |
|
|
| `Access-Control-Allow-Credentials` | `true` |
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Required | Default | Description |
|
|
|----------|----------|---------|-------------|
|
|
| `JWT_SECRET` | Yes | - | Secret key for JWT signing (min 32 chars, recommend 64+) |
|
|
| `DB_HOST` | Yes | - | PostgreSQL host |
|
|
| `DB_USER` | Yes | - | PostgreSQL user |
|
|
| `DB_PASSWORD` | Yes | - | PostgreSQL password |
|
|
| `DB_NAME` | Yes | - | PostgreSQL database name |
|
|
| `DB_SSL_MODE` | No | `require` | SSL mode: `disable`, `require`, `verify-ca`, `verify-full` |
|
|
| `DB_SCHEMA` | No | `public` | Schema: `dev`, `testing`, `prod` |
|
|
| `CORS_ALLOW_ORIGIN` | No | `http://localhost:8090` | Allowed CORS origin |
|
|
| `DEFAULT_USER_ROLE` | No | `CLIENT` | Default role for new users |
|
|
|
|
---
|
|
|
|
## Database Tables
|
|
|
|
### users
|
|
```sql
|
|
CREATE TABLE users (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
email VARCHAR(255) UNIQUE,
|
|
is_initial_superuser BOOLEAN DEFAULT false,
|
|
is_protected BOOLEAN DEFAULT false,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### identities
|
|
```sql
|
|
CREATE TABLE identities (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
type identity_type NOT NULL, -- 'email_password', 'blockchain_address', 'did'
|
|
identifier VARCHAR(500) NOT NULL,
|
|
credential TEXT, -- Password hash or other credential
|
|
is_primary_login BOOLEAN DEFAULT false,
|
|
metadata JSONB,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(type, identifier)
|
|
);
|
|
```
|
|
|
|
### user_roles
|
|
```sql
|
|
CREATE TABLE user_roles (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
role user_role NOT NULL, -- 'SUPERUSER', 'ADMIN', 'STAFF', 'CLIENT'
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(user_id, role)
|
|
);
|
|
```
|
|
|
|
### superuser_transfers
|
|
```sql
|
|
CREATE TABLE superuser_transfers (
|
|
id SERIAL PRIMARY KEY,
|
|
from_user_id INTEGER NOT NULL REFERENCES users(id),
|
|
to_user_id INTEGER NOT NULL REFERENCES users(id),
|
|
transferred_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
reason TEXT
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## Security Considerations
|
|
|
|
1. **Password Storage**: Passwords are hashed using bcrypt with default cost
|
|
2. **JWT Security**: Tokens expire after 24 hours, signed with HS256
|
|
3. **First User Protection**: Initial superuser cannot be deleted, only transferred
|
|
4. **Role Hierarchy**: ADMINs cannot modify SUPERUSERs
|
|
5. **Audit Logging**: All role changes and transfers are logged
|
|
6. **Input Validation**: All inputs are validated and sanitized
|
|
7. **SQL Injection**: All queries use parameterized statements
|