feat: add API key authentication and update tests
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

Adds `VerifyApiKey` middleware protecting all API routes with `X-Api-Key` header validation. Wraps `/api/stations`, `/api/stats/searches`, and `/api/prediction` in throttled middleware group (60 req/min). Updates StationSearchTest to use `RefreshDatabase`, adds `meta` assertion checks, and validates `fuel_type` in HTTP request assertions. Removes auth routes from API docs and replaces with API key authentication instructions. Adds `api_secret_key` config option.
This commit is contained in:
Ovidiu U
2026-04-05 20:27:41 +01:00
parent 1318e3ac3b
commit 1860cf0a49
3 changed files with 31 additions and 97 deletions

View File

@@ -1,7 +1,15 @@
# FuelAlert API Reference
Base URL: `https://fuel-price.test/api`
All endpoints return JSON. No auth required on public endpoints (same-origin only for now — token auth planned).
All endpoints return JSON. All endpoints require an `X-Api-Key` header.
**Authentication:**
```
X-Api-Key: your-secret-key
```
All requests without a valid key return `403 Forbidden`.
---
@@ -24,9 +32,18 @@ Returns nearby petrol stations with live prices for a given fuel type.
|---|---|---|---|
| `fuel_type` | string | — | **Required.** See fuel type aliases below |
| `radius` | float | `10.0` | Search radius in km (0.150) |
| `sort` | string | `"price"` | `"price"` or `"distance"` |
| `sort` | string | `"price"` | `"price"`, `"distance"`, `"updated"`, or `"brand"` |
| `pricing_mode` | string | — | `"pump"` (reserved, no effect yet) |
**Sort values:**
| Value | Sorts by |
|---|---|
| `price` | Price ascending (cheapest first) — **default** |
| `distance` | Distance ascending (closest first) |
| `updated` | Price freshness descending (most recently updated first) |
| `brand` | Brand name AZ |
**Fuel type aliases** (`fuel_type` accepts any of these):
| Alias | Maps to |
@@ -42,6 +59,8 @@ Returns nearby petrol stations with live prices for a given fuel type.
```
GET /api/stations?postcode=SW1A1AA&fuel_type=petrol&radius=5&sort=price
GET /api/stations?lat=51.5074&lng=-0.1278&fuel_type=diesel&radius=10&sort=distance
GET /api/stations?postcode=M11AE&fuel_type=petrol&sort=updated
GET /api/stations?postcode=M11AE&fuel_type=petrol&sort=brand
```
**Response:**
@@ -244,96 +263,6 @@ GET /api/prediction?fuel_type=petrol&lat=51.5074&lng=-0.1278
---
## Auth
> **Note:** Auth routes are implemented (`AuthController` exists) but not yet wired into `routes/api.php`. Add when token-based access is needed.
### POST `/api/auth/register`
Create a new account and receive a Sanctum token.
**Body (JSON):**
```json
{
"name": "Jane Smith",
"email": "jane@example.com",
"password": "secret123",
"password_confirmation": "secret123"
}
```
**Response `201`:**
```json
{
"token": "1|abc123...",
"user": {
"id": 42,
"name": "Jane Smith",
"email": "jane@example.com",
"created_at": "2026-04-05T10:00:00.000000Z"
}
}
```
---
### POST `/api/auth/login`
**Body (JSON):**
```json
{
"email": "jane@example.com",
"password": "secret123"
}
```
**Response `200`:**
```json
{
"token": "1|abc123...",
"user": { ... }
}
```
**Response `401` (wrong credentials):**
```json
{ "message": "Invalid credentials." }
```
---
### POST `/api/auth/logout`
Revokes the current token.
**Headers:** `Authorization: Bearer {token}`
**Response `200`:**
```json
{ "message": "Logged out." }
```
---
### GET `/api/auth/me`
Returns the authenticated user.
**Headers:** `Authorization: Bearer {token}`
**Response `200`:** Full `User` model JSON.
---
## Using the Token (when auth is wired up)
```
Authorization: Bearer 1|abc123...
```
All protected routes must include this header.
---
## Error Shapes
@@ -347,7 +276,7 @@ All protected routes must include this header.
}
```
**Unauthenticated (401):**
**Forbidden (403)** — missing or invalid `X-Api-Key`:
```json
{ "message": "Unauthenticated." }
{ "message": "Forbidden." }
```