porchlight/README.md

171 lines
4.3 KiB
Markdown

# Porchlight
OpenID Connect Provider with user management, built with FastAPI.
Porchlight handles user registration (via magic links), credential management
(passwords and WebAuthn security keys), and issues OIDC tokens for relying
parties. It uses SQLite for storage, Jinja2 + HTMX for the UI, and idpyoidc
for the OIDC protocol layer.
## Production Setup
### Docker (recommended)
```bash
docker compose --profile prod up --build
```
This starts Porchlight on port 8000 with 4 uvicorn workers. Data is persisted
in a named Docker volume.
Set required environment variables in `docker-compose.yml` or via `.env`:
```bash
OIDC_OP_ISSUER=https://auth.example.com
OIDC_OP_SESSION_SECRET=<random-secret>
```
### Manual
Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
```bash
uv sync --no-dev
OIDC_OP_ISSUER=https://auth.example.com \
OIDC_OP_SESSION_SECRET=$(python -c "import secrets; print(secrets.token_hex(32))") \
uv run uvicorn porchlight.app:create_app \
--factory --host 0.0.0.0 --port 8000 --workers 4
```
### Bootstrap the first admin user
After starting the app for the first time, create an admin account:
```bash
OIDC_OP_ISSUER=https://auth.example.com \
uv run porchlight initial-admin admin
```
This prints a one-time registration URL. Open it in a browser to set up
credentials (password or security key) for the admin user.
### CLI commands
Porchlight includes a CLI for administrative tasks. All commands read the same
`OIDC_OP_*` environment variables as the server.
**`porchlight create-invite <username>`** -- Generate a magic link registration
URL for a new user.
```bash
uv run porchlight create-invite alice
uv run porchlight create-invite alice --ttl 3600 --note "Onboarding"
```
| Option | Description |
|---|---|
| `--ttl SECONDS` | Link expiration (default: `OIDC_OP_INVITE_TTL`, 86400s) |
| `--note TEXT` | Optional note stored with the link |
**`porchlight initial-admin <username>`** -- Bootstrap the first admin user with
a registration link.
```bash
uv run porchlight initial-admin admin
uv run porchlight initial-admin admin --group admin --group superusers
```
| Option | Description |
|---|---|
| `--group TEXT` | Groups to assign (repeatable, default: `admin`, `users`) |
### Configuration
All settings are read from environment variables with the `OIDC_OP_` prefix:
| Variable | Default | Description |
|---|---|---|
| `OIDC_OP_ISSUER` | **required** | OIDC issuer URL (must match public URL) |
| `OIDC_OP_SESSION_SECRET` | random per process | Session cookie signing secret |
| `OIDC_OP_DEBUG` | `false` | Enable `/docs` Swagger UI |
| `OIDC_OP_SQLITE_PATH` | `data/oidc_op.db` | SQLite database path |
| `OIDC_OP_SIGNING_KEY_PATH` | `data/keys` | OIDC signing key storage |
| `OIDC_OP_INVITE_TTL` | `86400` | Magic link expiry in seconds |
| `OIDC_OP_MANAGE_CLIENT_ID` | `manage-app` | Client ID for the management UI |
Database migrations run automatically on startup.
## Development Setup
### Prerequisites
- Python 3.13+
- [uv](https://docs.astral.sh/uv/)
- Node.js (for e2e tests)
### Getting started
```bash
# Install dependencies (including dev tools)
uv sync
# Start the dev server with hot reload
OIDC_OP_ISSUER=http://localhost:8000 OIDC_OP_DEBUG=true \
uv run uvicorn porchlight.app:create_app \
--factory --host 127.0.0.1 --port 8000 --reload --reload-dir src
```
Or with Docker:
```bash
docker compose --profile dev up --build
```
### Running tests
```bash
# Unit/integration tests
uv run pytest
# Lint and format
uv run ruff check src/ tests/ --fix
uv run ruff format src/ tests/
# Type checking
uv run ty check src/
```
### End-to-end browser tests
The e2e suite uses Playwright (Node.js) to test all user-facing flows against a
running instance of the app.
```bash
# One-time setup: install Playwright and Chromium
cd tests/e2e
npm install && npm run setup
cd ../..
# Run all e2e tests
./tests/e2e/run.sh
# Run a specific test
./tests/e2e/run.sh tests/e2e/test_login.js
# Run with visible browser (not headless)
E2E_HEADLESS=0 ./tests/e2e/run.sh
```
The runner starts the app on port 8099, seeds test fixtures into a temporary
SQLite database, runs all `test_*.js` files, and tears everything down.
### Full quality check
```bash
uv run ruff format src/ tests/
uv run ruff check src/ tests/ --fix
uv run ty check src/
uv run pytest
./tests/e2e/run.sh
```