This document describes the security mechanisms, authentication flows, and best practices implemented in the Clean Hono API.
- Authentication & Authorization
- Password Security
- Token Management
- Rate Limiting
- Input Validation
- Security Headers
- RBAC (Role-Based Access Control)
- Best Practices
The API uses JWT (JSON Web Tokens) for authentication. The authentication flow works as follows:
POST /auth/register
{
"name": "John Doe",
"email": "john@example.com",
"password": "SecurePass123!"
}
- Password is hashed using bcrypt before storage
- Email verification link is sent to the user
- User account is created but marked as unverified
POST /auth/verify-email
{
"token": "verification_token_from_email"
}
- Verifies user's email address
- Activates the account for login
POST /auth/login
{
"email": "john@example.com",
"password": "SecurePass123!"
}
Response:
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": "uuid",
"name": "John Doe",
"email": "john@example.com",
"role": "user"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}Include the JWT token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Protected routes require authentication. The AuthMiddleware validates JWT tokens and extracts user information.
Example Protected Route:
// All profile routes require authentication
ProfileRoutes.use("*", AuthMiddleware);For Login (Basic Validation):
- Minimum 8 characters
- Maximum 128 characters
For Registration/Password Changes (Strong Validation):
- Minimum 8 characters
- At least one uppercase letter (A-Z)
- At least one lowercase letter (a-z)
- At least one number (0-9)
- At least one special character (!@#$%^&*()_+-=[]{}|;:,.<>?)
- Passwords are never stored in plain text
- Passwords are hashed using bcrypt with automatic salt generation
- Hash rounds are configured for optimal security/performance balance
POST /auth/forgot-password
{
"email": "user@example.com"
}
- Sends password reset link to email
- Token expires after a configured time period (default: 1 hour)
- For security, same response is returned whether email exists or not
POST /auth/reset-password
{
"token": "reset_token_from_email",
"password": "NewSecure123!"
}
- Validates reset token
- Ensures new password meets strong password requirements
- Invalidates old tokens after successful reset
PUT /profile/password
Authorization: Bearer <jwt_token>
{
"current_password": "OldPass123!",
"new_password": "NewSecure123!"
}
- Requires current password verification
- New password must be different from current password
- New password must meet strong password requirements
{
"sub": "user_uuid",
"email": "user@example.com",
"role": "user",
"permissions": ["user.read", "user.update"],
"iat": 1640000000,
"exp": 1640086400
}- Access Token: Short-lived token for API requests (default: 24 hours)
- Refresh Token: Long-lived token for obtaining new access tokens (default: 7 days)
All authenticated endpoints validate:
- Token signature
- Token expiration
- User existence
- User active status
Tokens can be invalidated through:
- Password change (invalidates all existing tokens)
- Logout (server-side token blacklisting via Redis)
- Admin action (account suspension)
Rate limiting is implemented to prevent abuse and brute force attacks.
| Endpoint Type | Limit | Window |
|---|---|---|
| Authentication endpoints | 5 requests | 15 minutes |
| Profile updates | 10 requests | 1 hour |
| General API | 100 requests | 15 minutes |
Responses include rate limit information:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000
{
"success": false,
"message": "Too many requests. Please try again later.",
"data": null
}All API inputs are validated using Zod schemas with OpenAPI integration.
- Type Validation: Ensures correct data types
- Format Validation: Email format, UUID format, etc.
- Business Rules: Password strength, min/max lengths
- Custom Validation: Complex validation logic
{
"success": false,
"message": "Validation Error",
"data": null,
"errors": {
"email": ["Must be a valid email address"],
"password": [
"Password must be at least 8 characters",
"Password must contain uppercase, lowercase, number, and special character"
]
}
}| Field Type | Validation Rules |
|---|---|
| Valid email format, max 255 chars | |
| Password (basic) | Min 8 chars, max 128 chars |
| Password (strong) | Min 8 chars + complexity rules |
| UUID | Valid UUID v4 format |
| Name | Min 1 char, max 255 chars |
| Remarks | Optional, max 500 chars |
The API sets security headers on all responses:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
CORS is configured based on environment:
Development:
- Allows all origins for testing
- Credentials enabled
Production:
- Whitelist of allowed origins
- Credentials enabled for trusted domains only
The system implements hierarchical role-based access:
- Super Admin: Full system access
- Admin: Manage users and settings
- User: Standard user access
Granular permissions control specific actions:
user.read: View usersuser.create: Create usersuser.update: Update usersuser.delete: Delete usersrole.manage: Manage rolespermission.manage: Manage permissions
Routes can be protected with permission requirements:
import { HasPermission } from "@guards";
// Requires user.create permission
UserRoutes.use("/", HasPermission("user.create"));Routes can be protected with role requirements:
import { HasRole } from "@guards";
// Requires admin role
AdminRoutes.use("/", HasRole("admin"));-
Store tokens securely
- Use httpOnly cookies or secure storage
- Never expose tokens in URLs
- Clear tokens on logout
-
Handle token expiration
- Implement token refresh logic
- Gracefully handle 401 unauthorized responses
- Redirect to login when tokens expire
-
Use HTTPS
- Always use HTTPS in production
- Never send credentials over HTTP
-
Implement rate limit handling
- Respect rate limit headers
- Implement exponential backoff on failures
- Cache responses when appropriate
-
Validate responses
- Check response status codes
- Validate response data structure
- Handle errors gracefully
-
Never log sensitive data
- No passwords in logs
- Mask sensitive fields
- Use structured logging
-
Keep dependencies updated
- Regular security updates
- Monitor vulnerability databases
- Use automated dependency scanning
-
Use environment variables
- Never hardcode secrets
- Use different keys per environment
- Rotate keys regularly
-
Implement audit logging
- Log authentication attempts
- Log permission changes
- Log data access
-
Regular security audits
- Code reviews for security issues
- Penetration testing
- Vulnerability scanning
- JWT-based authentication
- Password hashing (bcrypt)
- Email verification
- Password reset with tokens
- Token expiration
- Secure password requirements
- Role-based access control (RBAC)
- Permission-based guards
- Middleware authentication
- Protected routes
- Zod schema validation
- OpenAPI integration
- Detailed error messages
- Type safety
- Request rate limiting
- Redis-backed rate limiter
- Per-endpoint limits
- Rate limit headers
- CORS configuration
- Security headers
- HTTPS enforcement
- Content type validation
- Structured logging (Pino)
- Request ID tracking
- Performance monitoring
- Error tracking
For security issues or vulnerabilities:
- Do not open public issues
- Contact: security@example.com
- Use responsible disclosure practices
- Allow reasonable time for fixes
For general security questions:
- Review this documentation
- Check the API documentation
- Contact: support@example.com
Last Updated: February 8, 2026
Version: 1.0.0