diff --git a/.env.example b/.env.example index 2d49db1..825cd1d 100644 --- a/.env.example +++ b/.env.example @@ -9,4 +9,7 @@ MONGODB_URI=mongodb://:@localhost:27017/transaction_ledger?authS # keep: Keep transactions after account deletion # cascade: Delete transactions after account deletion # deny: Deny deletion of the account -TRANSACTION_DELETE_POLICY=keep \ No newline at end of file +TRANSACTION_DELETE_POLICY=keep + +# API keys for authentication +API_KEYS=your_api_key_1,your_api_key_2 \ No newline at end of file diff --git a/README.md b/README.md index b7947b6..fa06512 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,20 @@ http://localhost:/docs Replace `` with the configured port in your `.env` file. +## API Authentication + +The API is secured using API keys. Each request must include a valid API key in the `x-api-key` header. The API keys are configured in the environment variable `API_KEYS` as a comma-separated list. + +### Example Request + +Include the `x-api-key` header in your request: + +```bash +curl -X GET "http://localhost:/transactions" -H "x-api-key: YOUR_API_KEY" +``` + +Replace `` with the configured port in your `.env` file and `YOUR_API_KEY` with a valid API key. + ## Debugging with Visual Studio Code To launch and debug the API using Visual Studio Code, follow these steps: diff --git a/src/config/environment.ts b/src/config/environment.ts index 6358749..e650d84 100644 --- a/src/config/environment.ts +++ b/src/config/environment.ts @@ -9,6 +9,7 @@ export default () => { NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), MONGODB_URI: z.string().url(), TRANSACTION_DELETE_POLICY: z.enum(['keep', 'cascade', 'deny']).default('keep'), + API_KEYS: z.string().optional(), }); const env = envSchema.safeParse(process.env); diff --git a/src/middleware/apiKeyValidator.ts b/src/middleware/apiKeyValidator.ts new file mode 100644 index 0000000..9b05106 --- /dev/null +++ b/src/middleware/apiKeyValidator.ts @@ -0,0 +1,21 @@ +import type { Request, Response, NextFunction } from 'express'; + +const apiKeyValidator = (req: Request, res: Response, next: NextFunction) => { + const apiKey = req.header('x-api-key'); + + if (!process.env.API_KEYS) { + res.status(500).json({ error: 'API keys are not configured.' }); + return; + } + + const allowedKeys = process.env.API_KEYS.split(','); + + if (!apiKey || !allowedKeys.includes(apiKey)) { + res.status(401).json({ error: 'Unauthorized: Invalid API key.' }); + return; + } + + next(); +}; + +export default apiKeyValidator; diff --git a/src/routes/index.ts b/src/routes/index.ts index 1e1d737..1c5fb12 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,9 +1,11 @@ import express from 'express'; +import apiKeyValidator from '@/middleware/apiKeyValidator'; import accountRoutes from './account'; import transactionRoutes from './transaction'; const app = express(); +app.use(apiKeyValidator); app.use('/transactions', transactionRoutes); app.use('/accounts', accountRoutes); diff --git a/swagger.json b/swagger.json index 7c116e2..b27d579 100644 --- a/swagger.json +++ b/swagger.json @@ -639,6 +639,18 @@ } } } + }, + "securitySchemes": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key" + } + } + }, + "security": [ + { + "ApiKeyAuth": [] } - } + ] }