Add stage 1: authentication REST API
Slim 4 + SQLite todo-list API providing email/password registration, login, and an authenticated GET /me endpoint. Stateless HS256 JWTs, bcrypt password hashing, uniform JSON error envelope, and a SQL migration runner. Includes PHPUnit feature tests and stage-1 docs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# Stage 1 — Authentication API
|
||||
|
||||
Status: **done** and verified end-to-end (PHPUnit feature tests + a live `curl`
|
||||
run against the built-in server).
|
||||
|
||||
## What's there
|
||||
|
||||
A Slim 4 REST API on SQLite with JWT bearer authentication.
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| GET | `/api/health` | liveness check |
|
||||
| POST | `/api/auth/register` | create account, returns user + token |
|
||||
| POST | `/api/auth/login` | exchange email/password for a token |
|
||||
| GET | `/api/me` | current user (requires `Authorization: Bearer <jwt>`) |
|
||||
|
||||
- **Passwords** are hashed with `password_hash()` (bcrypt). Validation is
|
||||
email-format plus an 8–72 character password. Login returns a single generic
|
||||
"Invalid email or password" message so it does not leak which emails exist.
|
||||
- **Emails** are stored lower-cased in a `UNIQUE COLLATE NOCASE` column;
|
||||
duplicate registration returns `409`.
|
||||
- **Errors** always come back as
|
||||
`{ "error": { "message": ..., "details"?: ... } }` via
|
||||
[../src/Http/JsonErrorHandler.php](../src/Http/JsonErrorHandler.php).
|
||||
- **Tokens** are stateless HS256 JWTs. The signing secret comes from
|
||||
`JWT_SECRET`, or is auto-generated into `storage/secret.key` on first run.
|
||||
- **Migrations** are plain SQL files in [../migrations/](../migrations/), applied
|
||||
idempotently by [../bin/migrate.php](../bin/migrate.php) and tracked in a
|
||||
`schema_migrations` table.
|
||||
|
||||
## Dependency note
|
||||
|
||||
`firebase/php-jwt` is pinned to `^7.0` — Composer blocks `6.10`–`6.11` for a
|
||||
published security advisory (`PKSA-y2cr-5h3j-g3ys`).
|
||||
|
||||
## Key files
|
||||
|
||||
- [../src/bootstrap.php](../src/bootstrap.php) — app wiring + routes
|
||||
- [../src/Http/Controllers/AuthController.php](../src/Http/Controllers/AuthController.php) — register / login / me
|
||||
- [../src/Auth/JwtService.php](../src/Auth/JwtService.php), [../src/Auth/AuthMiddleware.php](../src/Auth/AuthMiddleware.php)
|
||||
- [../src/Repository/UserRepository.php](../src/Repository/UserRepository.php)
|
||||
- [../src/Support/Config.php](../src/Support/Config.php), [../src/Support/Database.php](../src/Support/Database.php)
|
||||
- [../tests/AuthTest.php](../tests/AuthTest.php) — 6 passing feature tests
|
||||
|
||||
## Run it
|
||||
|
||||
```bash
|
||||
composer install && composer migrate && composer serve # http://localhost:8080
|
||||
```
|
||||
|
||||
## Local toolchain
|
||||
|
||||
This machine has no `php`/`composer` binary. Tooling was run through the official
|
||||
Composer container image, which bundles PHP + Composer + `pdo_sqlite` +
|
||||
`mbstring`:
|
||||
|
||||
```bash
|
||||
podman run --rm -v "$PWD":/app:Z -w /app docker.io/library/composer:2 install
|
||||
podman run --rm -v "$PWD":/app:Z -w /app docker.io/library/composer:2 vendor/bin/phpunit
|
||||
```
|
||||
Reference in New Issue
Block a user