API Reference
This page documents all the API endpoints available in the FastAPI template.
Authentication Endpoints
All authentication endpoints are available under the root path /.
Register a New User
Endpoint: POST /register/
Creates a new user account and returns JWT and refresh tokens.
Request Body:
{
"email": "[email protected]",
"password": "securepassword123",
"first_name": "John",
"last_name": "Doe"
}
Response: 201 Created
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Notes:
- Email must be valid format
- Password must be at least 8 characters
- A verification email will be sent to the user's email address
- User must verify their email before accessing protected endpoints
- JWT token expires after 120 minutes
- Refresh token expires after 30 days
Login
Endpoint: POST /login/
Authenticates an existing user and returns JWT and refresh tokens.
Request Body:
{
"email": "[email protected]",
"password": "securepassword123"
}
Response: 200 OK
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Error Responses:
400 Bad Request: Invalid credentials401 Unauthorized: User is banned or not verified
Refresh Token
Endpoint: POST /refresh/
Generates a new JWT token using a valid refresh token.
Request Body:
{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response: 200 OK
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Token Validation:
- Maximum token length: 1024 characters
- Tokens must be valid JWT format (three dot-separated base64url parts)
- Empty tokens are rejected
- Malformed tokens are rejected before cryptographic verification
Security Features:
- Format Validation: Fast syntactic check before expensive crypto operations
- Length Validation: Tokens exceeding 1024 chars are rejected to prevent resource exhaustion
- Defense-in-depth: Multiple validation layers (format, length, cryptographic signature, token type)
- Early Rejection: Invalid formats fail fast with clear error messages
- Token Verification: Tokens are cryptographically verified (JWT with HS256)
- Type Checking: Only tokens with
typ="refresh"are accepted
Notes:
- The refresh token itself is not updated
- After 30 days, the user must login again with credentials
Verify Email
Endpoint: GET /verify/?code={token}
Verifies a user's email address using the token sent via email.
Query Parameters:
code(required): Verification token from email
Response: 200 OK
{
"detail": "User successfully Verified"
}
Token Validation:
- Maximum token length: 1024 characters
- Tokens must be valid JWT format (three dot-separated base64url parts)
- Empty tokens are rejected
- Malformed tokens are rejected before cryptographic verification
Security Features:
- Format Validation: Fast syntactic check before expensive crypto operations
- Length Validation: Tokens exceeding 1024 chars are rejected to prevent resource exhaustion
- Defense-in-depth: Multiple validation layers (format, length, cryptographic signature, token type)
- Early Rejection: Invalid formats fail fast with clear error messages
- Token Verification: Tokens are cryptographically verified (JWT with HS256)
- Type Checking: Only tokens with
typ="verify"are accepted - URL Parameter Safety: Validation occurs before processing URL parameters
Error Responses:
401 Unauthorized: Invalid, expired, or already used token, or malformed JWT404 Not Found: User not found
Forgot Password
Endpoint: POST /forgot-password/
Initiates a password reset by sending a reset email to the user.
Request Body:
{
"email": "[email protected]"
}
Response: 200 OK
{
"message": "Password reset email sent if user exists"
}
Notes:
- Always returns success to prevent email enumeration attacks
- If email exists and user is not banned, a reset email is sent
- Reset token expires after 30 minutes
- Banned users will not receive reset emails
Security Features:
- Email enumeration protection (always returns same response)
- Time-limited tokens (30 minute expiry)
- Banned users cannot reset passwords
Reset Password Form
Endpoint: GET /reset-password/?code={token}
Displays an HTML form for resetting password OR redirects to a custom frontend. This is the endpoint linked in password reset emails.
Query Parameters:
code(required): Password reset token from email
Response:
302 Redirect(ifFRONTEND_URLis configured) - Redirects to{FRONTEND_URL}/reset-password?code={token}200 OK(HTML) (ifFRONTEND_URLis not set) - Shows built-in password reset form
Built-in Form Behavior (no FRONTEND_URL):
Returns an HTML page with:
- Password reset form (if token is valid)
- Error message (if token is invalid/expired)
Error Messages:
- "Reset code is required" - No token provided
- "That token is Invalid" - Invalid token or banned user
- "That token has Expired" - Token expired (30 minutes)
Token Validation:
- Maximum token length: 1024 characters
- Tokens exceeding this limit will be rejected and show an error
- Empty tokens are rejected
- Invalid or malformed tokens show appropriate error messages
Security Features:
- URL Encoding: Reset tokens are URL-encoded before redirect to prevent injection attacks
- Length Validation: Tokens are validated for reasonable size to prevent resource exhaustion
- Redirect Safety: When
FRONTEND_URLis set, redirects only go to the configured domain with validated tokens - Token Verification: Tokens are cryptographically verified (JWT with HS256)
- Expiration: Reset tokens expire after 30 minutes
Notes:
- With custom frontend: Set
FRONTEND_URLin settings/env to redirect users to your app - Without custom frontend: Leave
FRONTEND_URLunset to use built-in form - Validates token before displaying the form (when using built-in form)
- Form submits to
POST /reset-password/ - Provides seamless integration with custom frontends while maintaining standalone functionality
Configuration:
To use with a custom frontend, set in .env:
FRONTEND_URL=https://app.example.com
Your frontend should:
- Handle the route
/reset-password - Extract the
codequery parameter - Display a custom password reset form
- POST to backend
/reset-password/with JSON:{"code": "...", "new_password": "..."}
Reset Password (API)
Endpoint: POST /reset-password/
Resets a user's password using the token received via email. Accepts both JSON (for API clients) and form data (from HTML form).
Request Body (JSON):
{
"code": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"new_password": "mynewsecurepassword456"
}
Request Body (Form Data):
code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
new_password=mynewsecurepassword456
Response (JSON): 200 OK
{
"message": "Password successfully reset"
}
Response (HTML): 200 OK
Returns an HTML success page when using form data submission.
Validation:
- New password must be at least 8 characters
Error Responses:
401 Unauthorized: Invalid, expired, or wrong token type401 Unauthorized: User is banned404 Not Found: User not found422 Validation Error: Password too short or invalid request data
Notes:
- Token must be of type "reset" (verification tokens won't work)
- Banned users cannot reset their password
- After successful reset, users can login with the new password
- JSON requests return JSON responses
- Form data requests return HTML pages
User Management Endpoints
Get Current User
Endpoint: GET /users/me
Authentication: Required (JWT or API Key)
Returns the currently authenticated user's information.
Response: 200 OK
{
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe"
}
Notes:
- Non-admin users only see their own basic information
- Admin users can use
/users/to see full details
Get User(s)
Endpoint: GET /users/
Authentication: Required ⚠️ Admin Only
Get all users or a specific user by their ID.
Query Parameters:
user_id(optional): Specific user ID to retrieve
Response: 200 OK
[
{
"id": 1,
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"banned": false,
"verified": true
}
]
Notes:
- If
user_idis omitted, returns all users - If
user_idis provided, returns single user object (not array)
Search Users
Endpoint: GET /users/search
Authentication: Required ⚠️ Admin Only
Search for users with various criteria.
Query Parameters:
search_term(required): Search query stringfield(optional): Field to search ("all", "email", "first_name", "last_name") - default: "all"exact_match(optional): Use exact matching instead of partial - default: falsepage(optional): Page number (min: 1, default: 1)size(optional): Items per page (min: 1, max: 100, default: 50)
Response: 200 OK
{
"items": [
{
"id": 1,
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"banned": false,
"verified": true
}
],
"total": 25,
"page": 1,
"size": 50,
"pages": 1
}
Edit User
Endpoint: PUT /users/{user_id}
Authentication: Required (User or Admin)
Update the specified user's data.
Path Parameters:
user_id: ID of user to edit
Request Body:
{
"email": "[email protected]",
"password": "newpassword123",
"first_name": "Jane",
"last_name": "Smith"
}
Response: 200 OK
{
"email": "[email protected]",
"first_name": "Jane",
"last_name": "Smith"
}
Notes:
- Users can edit their own profile
- Admins can edit any user's profile
Change User Password
Endpoint: POST /users/{user_id}/password
Authentication: Required (User or Admin)
Change the password for the specified user.
Path Parameters:
user_id: ID of user whose password to change
Request Body:
{
"password": "mynewpassword123"
}
Response: 204 No Content
Notes:
- Users can change their own password
- Admins can change any user's password
Make User Admin
Endpoint: POST /users/{user_id}/make-admin
Authentication: Required ⚠️ Admin Only
Grant admin role to the specified user.
Path Parameters:
user_id: ID of user to make admin
Response: 204 No Content
Ban User
Endpoint: POST /users/{user_id}/ban
Authentication: Required ⚠️ Admin Only
Ban the specified user. Banned users cannot login or access protected routes.
Path Parameters:
user_id: ID of user to ban
Response: 204 No Content
Notes:
- Admins cannot ban themselves
- Banned users cannot reset passwords or access any authenticated endpoints
Unban User
Endpoint: POST /users/{user_id}/unban
Authentication: Required ⚠️ Admin Only
Remove ban from the specified user.
Path Parameters:
user_id: ID of user to unban
Response: 204 No Content
Delete User
Endpoint: DELETE /users/{user_id}
Authentication: Required ⚠️ Admin Only
Permanently delete the specified user.
Path Parameters:
user_id: ID of user to delete
Response: 204 No Content
Error Responses:
400 Bad Request: Returned when attempting to delete the last admin user
{
"detail": "Cannot delete the last admin user"
}
Notes:
- This action is permanent and cannot be undone
- All associated API keys will also be deleted
- Admin Protection: The system prevents the last admin from deleting themselves to avoid system lockout. Admins can delete themselves only when multiple admin users exist
- Regular users can always be deleted by admins regardless of admin count
API Key Endpoints
List API Keys (Own)
Endpoint: GET /users/keys
Authentication: Required (JWT or API Key)
Returns all API keys for the authenticated user.
Response: 200 OK
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My API Key",
"created_at": "2026-01-01T12:00:00Z",
"is_active": true,
"scopes": ["read", "write"]
}
]
Note: The actual key value is never returned after creation.
Create API Key
Endpoint: POST /users/keys
Authentication: Required (JWT or API Key)
Creates a new API key for the authenticated user.
Request Body:
{
"name": "My API Key",
"scopes": ["read", "write"]
}
Response: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My API Key",
"key": "pk_abcdef123456...",
"created_at": "2026-01-01T12:00:00Z",
"is_active": true,
"scopes": ["read", "write"]
}
Important:
- The
keyfield is only returned once during creation - Store it securely - it cannot be retrieved again
- Use the key in the
X-API-Keyheader for authentication
Get Specific API Key
Endpoint: GET /users/keys/{key_id}
Authentication: Required (JWT or API Key)
Get details of a specific API key by ID.
Path Parameters:
key_id: UUID of the API key
Response: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My API Key",
"created_at": "2026-01-01T12:00:00Z",
"is_active": true,
"scopes": ["read", "write"]
}
Update API Key
Endpoint: PATCH /users/keys/{key_id}
Authentication: Required (JWT or API Key)
Update an API key's name or active status.
Path Parameters:
key_id: UUID of the API key
Request Body:
{
"name": "Updated Key Name",
"is_active": false
}
Response: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Updated Key Name",
"created_at": "2026-01-01T12:00:00Z",
"is_active": false,
"scopes": ["read", "write"]
}
Notes:
- Both fields are optional in the request
- Setting
is_activetofalsedisables the key without deleting it
Delete API Key
Endpoint: DELETE /users/keys/{key_id}
Authentication: Required (JWT or API Key)
Permanently delete an API key.
Path Parameters:
key_id: UUID of the API key
Response: 204 No Content
List User API Keys (Admin)
Endpoint: GET /users/keys/by-user/{user_id}
Authentication: Required ⚠️ Admin Only
List all API keys for a specific user.
Path Parameters:
user_id: ID of the user
Response: 200 OK
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "User's API Key",
"created_at": "2026-01-01T12:00:00Z",
"is_active": true,
"scopes": ["read", "write"]
}
]
Update User API Key (Admin)
Endpoint: PATCH /users/keys/by-user/{user_id}/{key_id}
Authentication: Required ⚠️ Admin Only
Update another user's API key.
Path Parameters:
user_id: ID of the userkey_id: UUID of the API key
Request Body:
{
"name": "Admin Updated Name",
"is_active": false
}
Response: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Admin Updated Name",
"created_at": "2026-01-01T12:00:00Z",
"is_active": false,
"scopes": ["read", "write"]
}
Delete User API Key (Admin)
Endpoint: DELETE /users/keys/by-user/{user_id}/{key_id}
Authentication: Required ⚠️ Admin Only
Delete another user's API key.
Path Parameters:
user_id: ID of the userkey_id: UUID of the API key
Response: 204 No Content
Health Endpoints
Heartbeat
Endpoint: GET /heartbeat
Returns a minimal response to confirm the service is up.
Response: 200 OK
{
"status": "ok"
}
Metrics
Endpoint: GET /metrics
Authentication: None required
Exposes Prometheus-compatible metrics for application observability. This endpoint is only available when metrics collection is enabled via the METRICS_ENABLED environment variable.
Response: 200 OK (text/plain; Prometheus format)
# HELP api_template_http_requests_total Total number of HTTP requests
# TYPE api_template_http_requests_total counter
api_template_http_requests_total{handler="/users/",method="GET",status="2xx"} 1542.0
# HELP api_template_http_request_duration_highr_seconds HTTP request latency
# TYPE api_template_http_request_duration_highr_seconds histogram
api_template_http_request_duration_highr_seconds_bucket{handler="/users/",method="GET",le="0.01"} 892.0
api_template_http_request_duration_highr_seconds_bucket{handler="/users/",method="GET",le="0.025"} 1420.0
api_template_http_request_duration_highr_seconds_sum{handler="/users/",method="GET"} 18.234
api_template_http_request_duration_highr_seconds_count{handler="/users/",method="GET"} 1542.0
# HELP api_template_auth_failures_total Total authentication failures
# TYPE api_template_auth_failures_total counter
api_template_auth_failures_total{method="jwt",reason="expired_token"} 15.0
api_template_auth_failures_total{method="jwt",reason="invalid_token"} 8.0
# HELP api_template_login_attempts_total Total login attempts by status
# TYPE api_template_login_attempts_total counter
api_template_login_attempts_total{status="success"} 892.0
api_template_login_attempts_total{status="invalid_password"} 24.0
Configuration:
To enable metrics, set in your .env file:
METRICS_ENABLED=true
Available Metrics:
- HTTP Performance Metrics:
{api_title}_http_requests_total- Total HTTP requests (counter){api_title}_http_request_duration_highr_seconds- Request latency (histogram){api_title}_http_requests_inprogress- In-flight requests (gauge){api_title}_http_request_size_bytes- Request body sizes (summary)-
{api_title}_http_response_size_bytes- Response body sizes (summary) -
Business Metrics:
{api_title}_auth_failures_total- Authentication failures by reason and method{api_title}_api_key_validations_total- API key validation attempts by status{api_title}_login_attempts_total- Login attempts by status
Notes:
- Metric namespace is derived from your
API_TITLEsetting (e.g.,api_template_) - The
/metricsand/heartbeatendpoints are excluded from HTTP metrics tracking - When disabled (
METRICS_ENABLED=false), this endpoint returns 404 Not Found - See Metrics and Observability for complete documentation
Authentication Methods
The API supports two authentication methods:
1. JWT Bearer Token
Include the JWT token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
- Token expires after 120 minutes
- Can be refreshed using refresh token
- Obtained from
/register/or/login/endpoints
2. API Key
Include the API key in the X-API-Key header:
X-API-Key: pk_abcdef123456...
- Does not expire (currently)
- Can be created/revoked by users
- Multiple keys per user supported
Error Responses
All endpoints may return the following error responses:
400 Bad Request
Invalid request data or parameters.
{
"detail": "Invalid credentials"
}
401 Unauthorized
Missing or invalid authentication credentials.
{
"detail": "That token is Invalid"
}
403 Forbidden
User lacks required permissions.
{
"detail": "Not enough permissions"
}
404 Not Found
Requested resource not found.
{
"detail": "User not Found"
}
422 Validation Error
Request validation failed.
{
"detail": [
{
"loc": ["body", "password"],
"msg": "ensure this value has at least 8 characters",
"type": "value_error.any_str.min_length"
}
]
}
Rate Limiting
Currently, there is no rate limiting implemented. This is planned for a future release.
Interactive Documentation
FastAPI provides automatic interactive API documentation:
- Swagger UI: Available at
/docs - ReDoc: Available at
/redoc
These interfaces allow you to explore and test all API endpoints interactively.