org
This commit is contained in:
613
kms/docs/API.md
Normal file
613
kms/docs/API.md
Normal file
@ -0,0 +1,613 @@
|
||||
# API Key Management Service - API Documentation
|
||||
|
||||
This document describes the REST API endpoints for the API Key Management Service.
|
||||
|
||||
## Base URL
|
||||
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
All protected endpoints require authentication via the `X-User-Email` header (when using the HeaderAuthenticationProvider).
|
||||
|
||||
```
|
||||
X-User-Email: user@example.com
|
||||
```
|
||||
|
||||
## Content Type
|
||||
|
||||
All endpoints accept and return JSON data:
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
## Error Response Format
|
||||
|
||||
All error responses follow this format:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Error Type",
|
||||
"message": "Detailed error message"
|
||||
}
|
||||
```
|
||||
|
||||
Common HTTP status codes:
|
||||
- `400` - Bad Request (invalid input)
|
||||
- `401` - Unauthorized (authentication required)
|
||||
- `404` - Not Found (resource not found)
|
||||
- `500` - Internal Server Error
|
||||
|
||||
## Health Check Endpoints
|
||||
|
||||
### Health Check
|
||||
```
|
||||
GET /health
|
||||
```
|
||||
|
||||
Basic health check for load balancers.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"timestamp": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Readiness Check
|
||||
```
|
||||
GET /ready
|
||||
```
|
||||
|
||||
Comprehensive readiness check including database connectivity.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ready",
|
||||
"timestamp": "2023-01-01T00:00:00Z",
|
||||
"checks": {
|
||||
"database": "healthy"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication Endpoints
|
||||
|
||||
### User Login
|
||||
```
|
||||
POST /api/login
|
||||
```
|
||||
|
||||
Initiates user authentication flow.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required for HeaderAuthenticationProvider)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.app",
|
||||
"permissions": ["repo.read", "repo.write"],
|
||||
"redirect_uri": "https://example.com/callback"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"redirect_url": "https://example.com/callback?token=user-token-abc123"
|
||||
}
|
||||
```
|
||||
|
||||
Or if no redirect_uri provided:
|
||||
```json
|
||||
{
|
||||
"token": "user-token-abc123",
|
||||
"user_id": "user@example.com",
|
||||
"app_id": "com.example.app",
|
||||
"expires_in": 604800
|
||||
}
|
||||
```
|
||||
|
||||
### Token Verification
|
||||
```
|
||||
POST /api/verify
|
||||
```
|
||||
|
||||
Verifies a token and returns its permissions.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.app",
|
||||
"type": "user",
|
||||
"user_id": "user@example.com",
|
||||
"token": "token-to-verify",
|
||||
"permissions": ["repo.read", "repo.write"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"user_id": "user@example.com",
|
||||
"permissions": ["repo.read", "repo.write"],
|
||||
"permission_results": {
|
||||
"repo.read": true,
|
||||
"repo.write": true
|
||||
},
|
||||
"expires_at": "2023-01-08T00:00:00Z",
|
||||
"max_valid_at": "2023-01-31T00:00:00Z",
|
||||
"token_type": "user"
|
||||
}
|
||||
```
|
||||
|
||||
### Token Renewal
|
||||
```
|
||||
POST /api/renew
|
||||
```
|
||||
|
||||
Renews a user token with extended expiration.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.app",
|
||||
"user_id": "user@example.com",
|
||||
"token": "current-token"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"token": "new-renewed-token",
|
||||
"expires_at": "2023-01-15T00:00:00Z",
|
||||
"max_valid_at": "2023-01-31T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Application Management
|
||||
|
||||
### List Applications
|
||||
```
|
||||
GET /api/applications?limit=50&offset=0
|
||||
```
|
||||
|
||||
Retrieves a paginated list of applications.
|
||||
|
||||
**Query Parameters:**
|
||||
- `limit` (optional): Number of results to return (default: 50, max: 100)
|
||||
- `offset` (optional): Number of results to skip (default: 0)
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"app_id": "com.example.app",
|
||||
"app_link": "https://example.com",
|
||||
"type": ["static", "user"],
|
||||
"callback_url": "https://example.com/callback",
|
||||
"hmac_key": "hmac-key-hidden-in-responses",
|
||||
"token_renewal_duration": 604800000000000,
|
||||
"max_token_duration": 2592000000000000,
|
||||
"owner": {
|
||||
"type": "team",
|
||||
"name": "Example Team",
|
||||
"owner": "example-org"
|
||||
},
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"limit": 50,
|
||||
"offset": 0,
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
### Create Application
|
||||
```
|
||||
POST /api/applications
|
||||
```
|
||||
|
||||
Creates a new application.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.newapp",
|
||||
"app_link": "https://newapp.example.com",
|
||||
"type": ["static", "user"],
|
||||
"callback_url": "https://newapp.example.com/callback",
|
||||
"token_renewal_duration": "168h",
|
||||
"max_token_duration": "720h",
|
||||
"owner": {
|
||||
"type": "team",
|
||||
"name": "Development Team",
|
||||
"owner": "example-org"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.newapp",
|
||||
"app_link": "https://newapp.example.com",
|
||||
"type": ["static", "user"],
|
||||
"callback_url": "https://newapp.example.com/callback",
|
||||
"hmac_key": "generated-hmac-key",
|
||||
"token_renewal_duration": 604800000000000,
|
||||
"max_token_duration": 2592000000000000,
|
||||
"owner": {
|
||||
"type": "team",
|
||||
"name": "Development Team",
|
||||
"owner": "example-org"
|
||||
},
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Get Application
|
||||
```
|
||||
GET /api/applications/{app_id}
|
||||
```
|
||||
|
||||
Retrieves a specific application by ID.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.app",
|
||||
"app_link": "https://example.com",
|
||||
"type": ["static", "user"],
|
||||
"callback_url": "https://example.com/callback",
|
||||
"hmac_key": "hmac-key-value",
|
||||
"token_renewal_duration": 604800000000000,
|
||||
"max_token_duration": 2592000000000000,
|
||||
"owner": {
|
||||
"type": "team",
|
||||
"name": "Example Team",
|
||||
"owner": "example-org"
|
||||
},
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Update Application
|
||||
```
|
||||
PUT /api/applications/{app_id}
|
||||
```
|
||||
|
||||
Updates an existing application. Only provided fields will be updated.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"app_link": "https://updated.example.com",
|
||||
"callback_url": "https://updated.example.com/callback",
|
||||
"owner": {
|
||||
"type": "individual",
|
||||
"name": "John Doe",
|
||||
"owner": "john.doe@example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"app_id": "com.example.app",
|
||||
"app_link": "https://updated.example.com",
|
||||
"type": ["static", "user"],
|
||||
"callback_url": "https://updated.example.com/callback",
|
||||
"hmac_key": "existing-hmac-key",
|
||||
"token_renewal_duration": 604800000000000,
|
||||
"max_token_duration": 2592000000000000,
|
||||
"owner": {
|
||||
"type": "individual",
|
||||
"name": "John Doe",
|
||||
"owner": "john.doe@example.com"
|
||||
},
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Application
|
||||
```
|
||||
DELETE /api/applications/{app_id}
|
||||
```
|
||||
|
||||
Deletes an application and all associated tokens.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Response:**
|
||||
```
|
||||
HTTP 204 No Content
|
||||
```
|
||||
|
||||
## Static Token Management
|
||||
|
||||
### List Tokens for Application
|
||||
```
|
||||
GET /api/applications/{app_id}/tokens?limit=50&offset=0
|
||||
```
|
||||
|
||||
Retrieves all static tokens for a specific application.
|
||||
|
||||
**Query Parameters:**
|
||||
- `limit` (optional): Number of results to return (default: 50, max: 100)
|
||||
- `offset` (optional): Number of results to skip (default: 0)
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"app_id": "com.example.app",
|
||||
"owner": {
|
||||
"type": "individual",
|
||||
"name": "John Doe",
|
||||
"owner": "john.doe@example.com"
|
||||
},
|
||||
"type": "hmac",
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"limit": 50,
|
||||
"offset": 0,
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
### Create Static Token
|
||||
```
|
||||
POST /api/applications/{app_id}/tokens
|
||||
```
|
||||
|
||||
Creates a new static token for an application.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"owner": {
|
||||
"type": "individual",
|
||||
"name": "API Client",
|
||||
"owner": "api-client@example.com"
|
||||
},
|
||||
"permissions": ["repo.read", "repo.write", "app.read"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"token": "static-token-abc123xyz789",
|
||||
"permissions": ["repo.read", "repo.write", "app.read"],
|
||||
"created_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** The `token` field is only returned once during creation for security reasons.
|
||||
|
||||
### Delete Static Token
|
||||
```
|
||||
DELETE /api/tokens/{token_id}
|
||||
```
|
||||
|
||||
Deletes a static token and revokes all its permissions.
|
||||
|
||||
**Headers:**
|
||||
- `X-User-Email: user@example.com` (required)
|
||||
|
||||
**Response:**
|
||||
```
|
||||
HTTP 204 No Content
|
||||
```
|
||||
|
||||
## Permission Scopes
|
||||
|
||||
The following permission scopes are available:
|
||||
|
||||
### System Permissions
|
||||
- `internal` - Full access to internal system operations (system only)
|
||||
- `internal.read` - Read access to internal system data (system only)
|
||||
- `internal.write` - Write access to internal system data (system only)
|
||||
- `internal.admin` - Administrative access to internal system (system only)
|
||||
|
||||
### Application Management
|
||||
- `app` - Access to application management
|
||||
- `app.read` - Read application information
|
||||
- `app.write` - Create and update applications
|
||||
- `app.delete` - Delete applications
|
||||
|
||||
### Token Management
|
||||
- `token` - Access to token management
|
||||
- `token.read` - Read token information
|
||||
- `token.create` - Create new tokens
|
||||
- `token.revoke` - Revoke existing tokens
|
||||
|
||||
### Permission Management
|
||||
- `permission` - Access to permission management
|
||||
- `permission.read` - Read permission information
|
||||
- `permission.write` - Create and update permissions
|
||||
- `permission.grant` - Grant permissions to tokens
|
||||
- `permission.revoke` - Revoke permissions from tokens
|
||||
|
||||
### Repository Access (Example)
|
||||
- `repo` - Access to repository operations
|
||||
- `repo.read` - Read repository data
|
||||
- `repo.write` - Write to repositories
|
||||
- `repo.admin` - Administrative access to repositories
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
The API implements rate limiting with the following limits:
|
||||
|
||||
- **General API endpoints**: 100 requests per minute with burst of 20
|
||||
- **Authentication endpoints** (`/login`, `/verify`, `/renew`): 10 requests per minute with burst of 5
|
||||
|
||||
Rate limit headers are included in responses:
|
||||
- `X-RateLimit-Limit`: Request limit per window
|
||||
- `X-RateLimit-Remaining`: Remaining requests in current window
|
||||
- `X-RateLimit-Reset`: Unix timestamp when the window resets
|
||||
|
||||
When rate limited:
|
||||
```json
|
||||
{
|
||||
"error": "Rate limit exceeded",
|
||||
"message": "Too many requests. Please try again later."
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Endpoints
|
||||
|
||||
For testing purposes, different user scenarios are available through different ports:
|
||||
|
||||
- **Port 80**: Regular user (`test@example.com`)
|
||||
- **Port 8081**: Admin user (`admin@example.com`) with higher rate limits
|
||||
- **Port 8082**: Limited user (`limited@example.com`) with lower rate limits
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Creating an Application and Static Token
|
||||
|
||||
1. **Create Application:**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/applications \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-Email: admin@example.com" \
|
||||
-d '{
|
||||
"app_id": "com.mycompany.api",
|
||||
"app_link": "https://api.mycompany.com",
|
||||
"type": ["static", "user"],
|
||||
"callback_url": "https://api.mycompany.com/callback",
|
||||
"token_renewal_duration": "168h",
|
||||
"max_token_duration": "720h",
|
||||
"owner": {
|
||||
"type": "team",
|
||||
"name": "API Team",
|
||||
"owner": "api-team@mycompany.com"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
2. **Create Static Token:**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/applications/com.mycompany.api/tokens \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-Email: admin@example.com" \
|
||||
-d '{
|
||||
"owner": {
|
||||
"type": "individual",
|
||||
"name": "Service Account",
|
||||
"owner": "service@mycompany.com"
|
||||
},
|
||||
"permissions": ["repo.read", "repo.write"]
|
||||
}'
|
||||
```
|
||||
|
||||
3. **Verify Token:**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/verify \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"app_id": "com.mycompany.api",
|
||||
"type": "static",
|
||||
"token": "static-token-abc123xyz789",
|
||||
"permissions": ["repo.read"]
|
||||
}'
|
||||
```
|
||||
|
||||
### User Authentication Flow
|
||||
|
||||
1. **Initiate Login:**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-Email: user@example.com" \
|
||||
-d '{
|
||||
"app_id": "com.mycompany.api",
|
||||
"permissions": ["repo.read"],
|
||||
"redirect_uri": "https://myapp.com/callback"
|
||||
}'
|
||||
```
|
||||
|
||||
2. **Verify User Token:**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/verify \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"app_id": "com.mycompany.api",
|
||||
"type": "user",
|
||||
"user_id": "user@example.com",
|
||||
"token": "user-token-from-login",
|
||||
"permissions": ["repo.read"]
|
||||
}'
|
||||
```
|
||||
|
||||
3. **Renew Token Before Expiry:**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/renew \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"app_id": "com.mycompany.api",
|
||||
"user_id": "user@example.com",
|
||||
"token": "current-user-token"
|
||||
}'
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- All tokens should be transmitted over HTTPS in production
|
||||
- Static tokens are returned only once during creation - store them securely
|
||||
- User tokens have both renewal and maximum validity periods
|
||||
- HMAC keys are used for token signing and should be rotated regularly
|
||||
- Rate limiting helps prevent abuse
|
||||
- Permission scopes follow hierarchical structure
|
||||
- All operations are logged with user attribution
|
||||
|
||||
## Development and Testing
|
||||
|
||||
The service includes comprehensive health checks, detailed logging, and metrics collection. When running with `LOG_LEVEL=debug`, additional debugging information is available in the logs.
|
||||
|
||||
For local development, the service can be started with:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
This starts PostgreSQL, the API service, and Nginx proxy with test user headers configured.
|
||||
Reference in New Issue
Block a user