API Key Management System built with NestJS - A secure and scalable solution for managing API keys with authentication, rotation, and access control.
- β User authentication with JWT
- β API key generation with cryptographic security
- β API key rotation and revocation
- β Maximum 3 active keys per user
- β Automatic key expiration (1 year default)
- β Access logging (bonus feature)
- β Rate limiting per API key (bonus feature)
- β 74%+ test coverage
- Framework: NestJS 9.x
- Runtime: Node.js 24.x
- Language: TypeScript 4.x
- Database: MongoDB Atlas (Cloud)
- Authentication: JWT (JSON Web Tokens)
- Password Hashing: bcrypt
- Testing: Jest + Supertest
- Containerization: Docker
- Node.js 24+ installed
- MongoDB Atlas account (or local MongoDB 7+)
- Yarn package manager
- Docker (optional, for containerization)
-
Clone the repository
git clone <repository-url> cd accesscore_service
-
Install dependencies
yarn install
-
Set up environment variables
Create a
.envfile in the root directory:# App NODE_ENV=development PORT=3000 # Database (MongoDB Atlas) MONGODB_URI=mongodb+srv://<username>:<password>@<cluster>.mongodb.net/accesscore?retryWrites=true&w=majority # JWT JWT_SECRET=your-super-secret-jwt-key-change-in-production JWT_EXPIRATION=24h # API Key Settings API_KEY_MAX_ACTIVE=3 API_KEY_DEFAULT_EXPIRATION_DAYS=365
Note: Replace
<username>,<password>, and<cluster>with your MongoDB Atlas credentials. -
Run database migrations
npx migrate-mongo up
yarn start:devServer runs on: http://localhost:3000
yarn build
yarn start:prodyarn start:debug# Build Docker image
docker build -t accesscore-service .
# Run container
docker run -p 3000:3000 --env-file .env accesscore-serviceyarn testyarn test:covCurrent coverage: 74.44%
yarn test:e2eImport the Postman collection for complete API documentation with examples:
File: AccessCore_API.postman_collection.json
Import Steps:
- Open Postman
- Click "Import" button
- Select the JSON file
- Collection will appear with all endpoints
POST /auth/register- Register a new userPOST /auth/login- Login and receive JWT token
POST /api-keys- Generate new API keyGET /api-keys- List all API keysDELETE /api-keys/:id- Revoke an API keyPOST /api-keys/:id/rotate- Rotate an API key
GET /access-logs- View audit logs of all API key operations
Rate limiting guards are implemented and ready to use:
Guards Available:
ApiKeyAuthGuard- Validates API keys fromx-api-keyorAuthorization: BearerheadersApiKeyRateLimitGuard- Enforces per-API-key rate limits (configurable, default 100 req/hour)
How to Use:
import { UseGuards } from '@nestjs/common';
import { ApiKeyAuthGuard } from './common/guards/api-key-auth.guard';
import { ApiKeyRateLimitGuard } from './common/guards/api-key-rate-limit.guard';
@Get('your-endpoint')
@UseGuards(ApiKeyAuthGuard, ApiKeyRateLimitGuard)
yourMethod() {
return { data: 'protected' };
}Features:
- Per-API-key rate limiting (not global)
- Configurable limits when generating keys (1-10000 requests/hour)
- Automatic request tracking via access logs
- Returns HTTP 429 when limit exceeded
- Supports both
x-api-keyandAuthorization: Bearerformats
-
Register a user
curl -X POST http://localhost:3000/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "Password123!" }'
-
Login
curl -X POST http://localhost:3000/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "Password123!" }'
Save the
accessTokenfrom response. -
Generate API Key
curl -X POST http://localhost:3000/api-keys \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -d '{ "name": "Production API Key", "rateLimit": 100 }'
Save the
keyfrom response. This key can be used by external apps to access protected endpoints.
- Password Requirements: Minimum 8 characters with uppercase, lowercase, number, and special character
- API Key Format:
ak_live_prefix + 64 character hex string - Hashing: bcrypt with 10 salt rounds for passwords and API keys
- JWT Expiration: 24 hours (configurable)
- Key Expiration: 1 year default (configurable)
- Max Active Keys: 3 per user (configurable)
- Rate Limiting: Configurable per API key (default: 100 requests/hour)
- Authentication: Supports both
x-api-keyheader andAuthorization: Bearerformat - CORS: Configurable origins for production, open in development
{
_id: ObjectId
email: string (unique)
password: string (hashed)
createdAt: Date
updatedAt: Date
}{
_id: ObjectId
userId: ObjectId (ref: User)
key: string (hashed)
prefix: string (visible, e.g., "ak_live_abc123")
name: string
status: "ACTIVE" | "REVOKED" | "EXPIRED"
rateLimit: number (requests per hour, default: 100)
expiresAt: Date
lastUsedAt: Date
revokedAt: Date
createdAt: Date
updatedAt: Date
}{
_id: ObjectId
apiKeyId: ObjectId (ref: ApiKey)
userId: ObjectId (ref: User)
endpoint: string
method: string
statusCode: number
ipAddress: string
userAgent: string
timestamp: Date
}src/
βββ modules/
β βββ auth/ # Authentication module
β βββ api-keys/ # API key management
β βββ access-logs/ # Access logging (bonus)
βββ common/
β βββ constants/ # App constants
β βββ decorators/ # Custom decorators
β βββ interceptors/ # Logging interceptor
β βββ utils/ # Crypto & hash utilities
βββ config/ # Configuration files
βββ app.module.ts
βββ main.ts
test/
βββ *.spec.ts # Unit tests
βββ *.e2e-spec.ts # E2E tests
migrations/ # Database migrations
Production: https://sxz4fpw7u6.us-east-1.awsapprunner.com
The application is containerized using Docker for easy deployment.
Build and run locally:
# Build image
docker build -t accesscore-service .
# Run container
docker run -p 3000:3000 --env-file .env accesscore-serviceDocker Compose (with MongoDB):
docker-compose up -dPlatform Options:
- AWS ECS Fargate (Serverless containers)
- AWS EC2 (Traditional instances)
- AWS App Runner (Simplified container deployment)
Database:
- MongoDB Atlas (Cloud-managed)
- AWS DocumentDB (AWS-managed MongoDB-compatible)
Deployment Steps:
- Build Docker image
- Push to AWS ECR (Elastic Container Registry)
- Create ECS task definition
- Deploy to ECS Fargate/EC2
- Configure Application Load Balancer
- Set up CloudWatch for logging and monitoring
- Create a cluster on MongoDB Atlas
- Create a database user with read/write permissions
- Whitelist IP addresses:
- For development: Your local IP
- For production:
0.0.0.0/0or specific AWS IPs
- Get connection string from Atlas dashboard
- Add connection string to
.envfile
Connection String Format:
mongodb+srv://<username>:<password>@<cluster>.mongodb.net/accesscore?retryWrites=true&w=majority
| Variable | Description | Default | Required |
|---|---|---|---|
NODE_ENV |
Environment mode | development |
No |
PORT |
Server port | 3000 |
No |
MONGODB_URI |
MongoDB Atlas connection string | - | Yes |
JWT_SECRET |
JWT signing secret | - | Yes |
JWT_EXPIRATION |
JWT token expiration | 24h |
No |
API_KEY_MAX_ACTIVE |
Max active keys per user | 3 |
No |
API_KEY_DEFAULT_EXPIRATION_DAYS |
Default key expiration | 365 |
No |
ALLOWED_ORIGINS |
CORS allowed origins (production) | - | No |
Current test coverage: 74.44%
- Per-API-Key Limits: Each API key has its own rate limit (default: 100 requests/hour)
- Configurable: Set custom rate limits when generating API keys (1-10000 requests/hour)
- Automatic Tracking: All API key requests are logged in the access logs
- Clear Errors: Returns HTTP 429 with descriptive message when limit exceeded
Generate API key with custom rate limit:
curl -X POST http://localhost:3000/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My API Key",
"rateLimit": 500
}'Apply guards to protect endpoints:
@Get('your-endpoint')
@UseGuards(ApiKeyAuthGuard, ApiKeyRateLimitGuard)
yourMethod() {
return { data: 'protected' };
}External apps access with API key:
# Using x-api-key header
curl -X GET http://localhost:3000/your-endpoint \
-H "x-api-key: YOUR_API_KEY"
# Using Authorization Bearer format
curl -X GET http://localhost:3000/your-endpoint \
-H "Authorization: Bearer YOUR_API_KEY"Rate limit exceeded response:
{
"statusCode": 429,
"message": "Rate limit exceeded. Maximum 100 requests per hour."
}The application includes a Dockerfile for containerization:
- Multi-stage build for optimized image size
- Node.js 24 Alpine base image
- Production-ready configuration
- Health check endpoint included
See Dockerfile for complete configuration.
-
Access Logs (Audit Trail)
- Tracks all API key operations
- Records endpoint, method, status code, IP, and user agent
- Queryable by user or API key
- Automatic logging via interceptor
-
Rate Limiting per API Key
- Configurable limits per API key (1-10000 requests/hour)
- Automatic request tracking via access logs
- Returns HTTP 429 when limit exceeded
- Supports both
x-api-keyandAuthorization: Bearerheaders - Apply to any endpoint using
@UseGuards(ApiKeyAuthGuard, ApiKeyRateLimitGuard)