feat(auth): Add authentication middleware

This commit is contained in:
Björn Benouarets
2026-02-06 00:08:27 +01:00
parent fb35450880
commit 78da787f43
5 changed files with 672 additions and 121 deletions

View File

@@ -36,6 +36,14 @@ routes:
strip_prefix:
enabled: true
prefix: "/api/v1"
security:
auth:
enabled: true
type: "api_key"
header: "X-Api-Key"
path:
include: []
exclude: []
```
## Sections
@@ -93,7 +101,7 @@ Links hosts to backend targets.
### Routes
Route definitions with path patterns and prefix stripping.
Route definitions with path patterns, prefix stripping, and authentication.
| Field | Type | Description |
|-------|------|-------------|
@@ -101,6 +109,7 @@ Route definitions with path patterns and prefix stripping.
| `api` | string | API ID to use for this route |
| `path` | string | Chi route pattern (e.g., `/api/v1/*`) |
| `strip_prefix` | object | Prefix stripping configuration |
| `security` | object | Security policies (auth) |
#### Strip Prefix
@@ -109,60 +118,123 @@ Route definitions with path patterns and prefix stripping.
| `enabled` | boolean | Enable prefix stripping |
| `prefix` | string | Prefix to remove from path |
#### Security
##### Authentication
| Field | Type | Description |
|-------|------|-------------|
| `enabled` | boolean | Enable authentication |
| `type` | string | Auth type identifier (for documentation) |
| `header` | string | Header name to validate (e.g., `X-Api-Key`, `Authorization`) |
| `path` | object | Path-based filtering configuration |
##### Auth Path Filtering
| Field | Type | Description |
|-------|------|-------------|
| `include` | array | Paths that require auth (empty = all, if set only these) |
| `exclude` | array | Paths that skip auth (only used if include is empty) |
**Path Filtering Logic:**
| Include | Exclude | Behavior |
|---------|---------|----------|
| Empty | Empty | Auth required for ALL paths |
| Set | Empty | Auth required ONLY for paths matching include |
| Empty | Set | Auth required for ALL EXCEPT paths matching exclude |
| Set | Set | Include takes precedence (same as "Set, Empty") |
**Wildcards in Path Patterns:**
- `*` matches any path
- `/api/*` matches `/api/` and any subpath
- `/api/v1/public/test/*` matches the prefix and any subpath
## Example Configurations
### Simple Proxy (No Prefix Stripping)
### Public API (No Auth)
```yaml
gateway:
host: "0.0.0.0"
port: 8080
features:
- logger
hosts:
- id: "host-001"
name: "localhost"
domain: "localhost:8080"
targets:
- id: "target-001"
name: "backend"
url: "https://api.example.com"
apis:
- id: "api-001"
host: "host-001"
target: "target-001"
routes:
- id: "route-001"
- id: "public-api"
api: "api-001"
path: "/api/*"
path: "/public/*"
strip_prefix:
enabled: true
prefix: "/public"
security:
auth:
enabled: false
```
**Request flow:**
- Client requests: `/api/users/123`
- Backend receives: `/api/users/123`
### Prefix Stripping
### Protected API (All Paths Require Auth)
```yaml
routes:
- id: "route-001"
- id: "protected-api"
api: "api-001"
path: "/api/v1/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
security:
auth:
enabled: true
header: "X-Api-Key"
path:
include: []
exclude: []
```
**Request flow:**
- Client requests: `/api/v1/users/123`
- Gateway strips: `/api/v1`
- Backend receives: `/users/123`
### Public with Protected Sub-paths (Include)
### Multiple Routes
```yaml
routes:
- id: "mixed-api"
api: "api-001"
path: "/api/*"
strip_prefix:
enabled: true
prefix: "/api"
security:
auth:
enabled: true
header: "X-Api-Key"
path:
include: ["/api/admin/*", "/api/users/*/profile"]
exclude: []
```
In this example:
- `/api/admin/users` → Requires auth (matches include)
- `/api/users/123/profile` → Requires auth (matches include)
- `/api/public/data` → No auth (doesn't match include)
- `/api/health` → No auth (doesn't match include)
### Protected with Public Sub-paths (Exclude)
```yaml
routes:
- id: "protected-with-public"
api: "api-001"
path: "/api/*"
security:
auth:
enabled: true
header: "Authorization"
path:
include: []
exclude: ["/api/health", "/api/public/*", "/api/v1/public/test/*"]
```
In this example:
- `/api/health` → No auth (matches exclude)
- `/api/public/data` → No auth (matches exclude)
- `/api/v1/public/test/123` → No auth (matches exclude)
- `/api/users` → Requires auth (doesn't match exclude)
- `/api/admin/settings` → Requires auth (doesn't match exclude)
### Multiple Routes with Different Auth
```yaml
routes:
@@ -172,49 +244,37 @@ routes:
strip_prefix:
enabled: true
prefix: "/public"
security:
auth:
enabled: false
- id: "api-route"
- id: "user-route"
api: "api-001"
path: "/api/v1/*"
path: "/users/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
```
prefix: "/users"
security:
auth:
enabled: true
header: "X-Api-Key"
path:
include: []
exclude: ["/users/login", "/users/register"]
### Multiple Backends
```yaml
hosts:
- id: "host-001"
name: "api-host"
domain: "api.example.com"
- id: "host-002"
name: "admin-host"
domain: "admin.example.com"
targets:
- id: "target-001"
name: "api-backend"
url: "https://api-backend.internal"
- id: "target-002"
name: "admin-backend"
url: "https://admin-backend.internal"
apis:
- id: "api-001"
host: "host-001"
target: "target-001"
- id: "api-002"
host: "host-002"
target: "target-002"
routes:
- id: "route-001"
- id: "admin-route"
api: "api-001"
path: "/api/*"
- id: "route-002"
api: "api-002"
path: "/admin/*"
strip_prefix:
enabled: true
prefix: "/admin"
security:
auth:
enabled: true
header: "Authorization"
path:
include: []
exclude: []
```
## Configuration Loading
@@ -244,3 +304,23 @@ The gateway uses chi/v5 routing patterns. Common patterns:
| `/files/*` | `/files/` and any subpath | `/files/doc.pdf` |
Note: `/*` matches zero or more path segments.
## Debug Logging
To see detailed authentication decisions, enable DEBUG logging in `main.go`:
```go
masterlog.SetLevel(masterlog.LevelDebug)
```
This will output logs like:
```json
{
"level": "debug",
"msg": "AuthMiddleware: Checking if path requires auth",
"path": "/api/v1/users",
"requires_auth": true,
"include": [],
"exclude": ["/api/v1/public/*"]
}
```