diff --git a/README.md b/README.md index aeccb77..f98a3d2 100644 --- a/README.md +++ b/README.md @@ -27,52 +27,60 @@ Any app that supports OpenID Connect can use ATAuth. No custom integration neede ## Features - **Standard OIDC Provider**: Discovery, authorization, token, userinfo, revocation, JWKS endpoints +- **Passkey Login**: WebAuthn/FIDO2 support -- users can register passkeys and skip the Bluesky OAuth flow - **Forward-Auth SSO Proxy**: nginx `auth_request` based single sign-on for any web service -- **Admin Dashboard**: Web UI with setup wizard for common self-hosted apps +- **Admin Dashboard**: Web UI with setup wizard for 20+ common self-hosted apps - **Access Control**: Per-user DID and handle pattern rules with deny-overrides - **PKCE Support**: Configurable per-client - **ES256 Signed JWTs**: Proper key rotation via JWKS endpoint ## Quick Start +### Prerequisites + +- Docker and Docker Compose +- A domain with a DNS record pointing to your server (e.g. `auth.yourdomain.com`) +- A reverse proxy that terminates TLS (Caddy, Traefik, or nginx) + ### 1. Clone and configure ```bash git clone https://github.com/Cache8063/atauth.git -cd atauth/gateway -cp .env.example .env +cd atauth +cp gateway/.env.example .env ``` -Edit `.env` -- replace `auth.yourdomain.com` with your actual domain in these fields: +Edit `.env` -- replace every instance of `auth.yourdomain.com` with your actual domain: ```env +# These must all use your real domain OAUTH_CLIENT_ID=https://auth.yourdomain.com/client-metadata.json OAUTH_REDIRECT_URI=https://auth.yourdomain.com/auth/callback OIDC_ISSUER=https://auth.yourdomain.com WEBAUTHN_RP_ID=auth.yourdomain.com WEBAUTHN_ORIGIN=https://auth.yourdomain.com +CORS_ORIGINS=https://app1.yourdomain.com,https://app2.yourdomain.com ``` -Generate and fill in the required secrets: +Generate and fill in the three required secrets (run the command once per value): ```bash -openssl rand -hex 32 # Use output for each value below +openssl rand -hex 32 ``` ```env -ADMIN_TOKEN= -OIDC_KEY_SECRET= -MFA_ENCRYPTION_KEY= +ADMIN_TOKEN= +OIDC_KEY_SECRET= +MFA_ENCRYPTION_KEY= ``` ### 2. Start the service ```bash -cd .. # back to repo root docker compose up -d ``` -The gateway runs on `127.0.0.1:3100`. It needs a reverse proxy with TLS in front of it. The simplest option is Caddy (auto-HTTPS): +The gateway starts on `127.0.0.1:3100`. Put a reverse proxy with TLS in front of it. The simplest option is [Caddy](https://caddyserver.com/) (automatic HTTPS): ```caddyfile auth.yourdomain.com { @@ -82,9 +90,30 @@ auth.yourdomain.com { See the [Homelab Deployment Guide](docs/HOMELAB.md) for Traefik and nginx examples. -### 3. Register your first app +### 3. Verify it's running + +```bash +curl https://auth.yourdomain.com/.well-known/openid-configuration +``` + +You should get a JSON document with all the OIDC endpoints. + +### 4. Register your first app + +Open `https://auth.yourdomain.com/admin/login`, enter your `ADMIN_TOKEN`, and use the setup wizard to register an app. The wizard includes presets that auto-fill redirect URIs, scopes, and grant types. + +Save the returned **client secret** -- it is only shown once. + +### 5. Configure your app -Open `https://auth.yourdomain.com/admin/login`, enter your admin token, and use the setup wizard to register an app. +Point your app's OIDC settings to ATAuth's discovery URL: + +| Setting | Value | +| --- | --- | +| Discovery URL | `https://auth.yourdomain.com/.well-known/openid-configuration` | +| Client ID | The ID you chose in the wizard | +| Client Secret | The secret returned at registration | +| Scopes | `openid profile` (add `email` if needed) | ## Supported Apps @@ -114,19 +143,16 @@ The setup wizard includes presets for: | FreshRSS | OIDC (built-in) | | Any web service | Forward-auth proxy (nginx `auth_request`) | -## OIDC Discovery +## Forward-Auth Proxy -Once running, your OIDC discovery document is at: +For apps without OIDC support, ATAuth provides nginx `auth_request` based SSO. Enable it in `.env`: -```text -https://your-domain/.well-known/openid-configuration +```env +FORWARD_AUTH_ENABLED=true +FORWARD_AUTH_SESSION_SECRET= ``` -Configure any OIDC-compatible app with this URL and it will auto-discover all endpoints. - -## Forward-Auth Proxy - -For apps without OIDC support, ATAuth provides an nginx `auth_request` proxy: +Then configure nginx: ```nginx location / { @@ -158,6 +184,8 @@ With a self-hosted PDS, ATAuth becomes a fully independent auth system: - Works on air-gapped networks - Same security model as enterprise OAuth +The gateway auto-discovers the user's PDS from their handle. No special configuration needed. + ## Architecture | Component | Description | diff --git a/docker-compose.yml b/docker-compose.yml index 706a5f2..578f6a7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,10 @@ # ATAuth - Self-Hosted AT Protocol Authentication # # Quick Start: -# 1. Copy .env.example to .env and configure -# 2. docker compose up -d -# 3. Register your first app via the admin API -# -# For use with your own PDS (recommended): -# - Set OAUTH_CLIENT_ID to your gateway's public URL -# - Point your apps to authenticate via this gateway -# - Users sign in with their AT Protocol handle (@user.your-pds.com) +# 1. cp gateway/.env.example .env +# 2. Edit .env -- set your domain and generate secrets +# 3. docker compose up -d +# 4. Open https://your-domain/admin/login services: atauth: @@ -19,25 +15,11 @@ services: container_name: atauth-gateway restart: unless-stopped ports: - # Bind to localhost only by default for security - # Use a reverse proxy (Traefik/Caddy) for external access + # Bind to localhost only -- use a reverse proxy for external access - "127.0.0.1:3100:3100" + env_file: .env environment: - # Gateway configuration - - PORT=3100 - - HOST=0.0.0.0 - - # OAuth client identity (your gateway's public URL) - - OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID:-https://auth.example.com/client-metadata.json} - - OAUTH_REDIRECT_URI=${OAUTH_REDIRECT_URI:-https://auth.example.com/auth/callback} - - # Admin API token (generate with: openssl rand -hex 32) - - ADMIN_TOKEN=${ADMIN_TOKEN} - - # CORS origins (comma-separated) - - CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:3000,http://localhost:5173} - - # Database path + # Override DB_PATH for container volume mount - DB_PATH=/app/data/gateway.db volumes: - atauth-data:/app/data @@ -48,7 +30,7 @@ services: retries: 3 start_period: 10s labels: - # Traefik labels (optional - uncomment if using Traefik) + # Traefik labels (uncomment if using Traefik) # - "traefik.enable=true" # - "traefik.http.routers.atauth.rule=Host(`auth.example.com`)" # - "traefik.http.routers.atauth.entrypoints=websecure" @@ -59,7 +41,6 @@ services: - "homepage.group=Authentication" - "homepage.name=ATAuth Gateway" - "homepage.icon=lock" - - "homepage.href=https://auth.example.com" - "homepage.description=AT Protocol SSO Gateway" volumes: diff --git a/docs/HOMELAB.md b/docs/HOMELAB.md index f05bbe0..ba0c76d 100644 --- a/docs/HOMELAB.md +++ b/docs/HOMELAB.md @@ -5,35 +5,39 @@ ATAuth provides OIDC-based authentication for your homelab using AT Protocol ide ## Prerequisites - Docker and Docker Compose -- A domain name with TLS (reverse proxy: Caddy, Traefik, or nginx) +- A domain name with DNS pointing to your server +- A reverse proxy that terminates TLS (Caddy, Traefik, or nginx) - Optional: Your own PDS for fully self-hosted identity ## Deploy ```bash git clone https://github.com/Cache8063/atauth.git -cd atauth/gateway -cp .env.example .env +cd atauth +cp gateway/.env.example .env ``` -Edit `.env` with your configuration. At minimum, set these required secrets: +Edit `.env`: -```bash -# Generate and paste each value -openssl rand -hex 32 # for ADMIN_TOKEN -openssl rand -hex 32 # for OIDC_KEY_SECRET -openssl rand -hex 32 # for MFA_ENCRYPTION_KEY (produces 64 hex chars) -``` +1. Replace every `auth.yourdomain.com` with your actual domain +2. Set `CORS_ORIGINS` to the domains of apps that will use ATAuth +3. Generate three secrets (`openssl rand -hex 32` for each) and fill in `ADMIN_TOKEN`, `OIDC_KEY_SECRET`, and `MFA_ENCRYPTION_KEY` -Also update `OAUTH_CLIENT_ID`, `OAUTH_REDIRECT_URI`, `OIDC_ISSUER`, and `WEBAUTHN_*` to match your domain. +See `gateway/.env.example` for all available options including email, forward-auth proxy, and passkey configuration. -Then start: +Start the gateway: ```bash docker compose up -d ``` -The gateway runs on port 3100. Put a reverse proxy with TLS in front of it. +The gateway runs on `127.0.0.1:3100`. Set up a reverse proxy with TLS (see [Reverse Proxy Configuration](#reverse-proxy-configuration) below). + +Verify it's running: + +```bash +curl https://your-atauth-domain/.well-known/openid-configuration +``` ## Register Apps @@ -43,6 +47,8 @@ Open `https://your-atauth-domain/admin/login`, enter your admin token, then use - Audiobookshelf, Jellyfin, Gitea/Forgejo, Nextcloud, Immich - Grafana, Wiki.js, Portainer, Outline, Mealie +- Paperless-ngx, Vaultwarden, Miniflux, Mattermost, Vikunja +- Plane, GoToSocial, Stirling-PDF, Tandoor Recipes, FreshRSS Each preset auto-fills the correct redirect URI, scopes, and grant types. @@ -84,7 +90,14 @@ This auto-discovers all endpoints. Most apps need: ## Forward-Auth Proxy -For apps without OIDC support, ATAuth provides nginx `auth_request` based SSO. +For apps without OIDC support, ATAuth provides nginx `auth_request` based SSO. Enable it in `.env`: + +```env +FORWARD_AUTH_ENABLED=true +FORWARD_AUTH_SESSION_SECRET= +``` + +Then: 1. Register the origin in the admin dashboard under **Proxy Origins** 2. Add access rules under **Access Rules** @@ -117,7 +130,7 @@ location = /auth/verify { ```caddyfile auth.example.com { - reverse_proxy atauth:3100 + reverse_proxy localhost:3100 } ``` @@ -143,7 +156,7 @@ server { ssl_certificate_key /etc/ssl/private/auth.example.com.key; location / { - proxy_pass http://atauth:3100; + proxy_pass http://localhost:3100; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -180,7 +193,7 @@ Manage rules via the admin dashboard or API. # Backup the SQLite database docker compose exec atauth cp /app/data/gateway.db /app/data/gateway.db.backup -# Or backup the volume +# Or backup the entire data volume docker run --rm -v atauth_atauth-data:/data -v $(pwd):/backup alpine \ tar czf /backup/atauth-backup.tar.gz -C /data . ``` @@ -206,14 +219,18 @@ docker compose up -d ### OIDC discovery returns 404 -Ensure your `OAUTH_CLIENT_ID` URL is publicly accessible and the gateway is running. +Ensure `OAUTH_CLIENT_ID` in `.env` matches your public URL and the gateway is running. Check logs with `docker compose logs atauth`. ### Users can't authenticate -1. Check the PDS is reachable from the ATAuth container +1. Check the PDS is reachable from the ATAuth container: `docker compose exec atauth wget -qO- https://bsky.social/xrpc/_health` 2. Verify the user's handle resolves correctly 3. Check logs: `docker compose logs atauth` ### "invalid_redirect_uri" The redirect URI in the OIDC request must exactly match one registered for the client (including scheme, host, port, and path). + +### CORS errors in browser console + +Add the app's origin to `CORS_ORIGINS` in `.env` and restart: `docker compose restart atauth`. diff --git a/gateway/.env.example b/gateway/.env.example index 07c9b02..ba02485 100644 --- a/gateway/.env.example +++ b/gateway/.env.example @@ -13,6 +13,7 @@ OAUTH_REDIRECT_URI=https://auth.yourdomain.com/auth/callback ADMIN_TOKEN= # Database Path (SQLite) +# Docker Compose overrides this to /app/data/gateway.db DB_PATH=./data/gateway.db # CORS Origins (comma-separated)