AtAuth
at main 232 lines 6.9 kB view raw view rendered
1# ATAuth - OIDC Provider for AT Protocol 2 3An OpenID Connect (OIDC) Provider that uses AT Protocol OAuth (Bluesky) as the identity source. Authenticate users via their `@handle` -- works with Bluesky or any self-hosted PDS. 4 5## What It Does 6 7ATAuth sits between your apps and AT Protocol identity: 8 9```text 10Your App (OIDC Client) 11 | 12 v 13ATAuth (OIDC Provider) 14 | 15 v 16User's PDS (Bluesky / self-hosted) 17 | 18 v 19User authenticates with their AT Proto identity 20 | 21 v 22ATAuth issues standard OIDC tokens back to your app 23``` 24 25Any app that supports OpenID Connect can use ATAuth. No custom integration needed. 26 27## Screenshots 28 29<!-- Add your own screenshots to docs/screenshots/ --> 30 31![Login - Sign in with your AT Protocol identity](docs/screenshots/login.png) 32 33![Admin Dashboard - Stats and quick actions](docs/screenshots/dashboard.png) 34 35![Setup Wizard - One-click setup for 20+ self-hosted apps](docs/screenshots/wizard.png) 36 37![Access Rules - Per-user control with DID and handle patterns](docs/screenshots/access-rules.png) 38 39## Features 40 41- **Standard OIDC Provider**: Discovery, authorization, token, userinfo, revocation, JWKS endpoints 42- **Passkey Login**: WebAuthn/FIDO2 support -- users can register passkeys and skip the Bluesky OAuth flow 43- **Forward-Auth SSO Proxy**: nginx `auth_request` based single sign-on for any web service 44- **Admin Dashboard**: Web UI with setup wizard for 20+ common self-hosted apps 45- **Access Control**: Per-user DID and handle pattern rules with deny-overrides 46- **PKCE Support**: Configurable per-client 47- **ES256 Signed JWTs**: Proper key rotation via JWKS endpoint 48 49## Quick Start 50 51### Prerequisites 52 53- Docker and Docker Compose 54- A domain with a DNS record pointing to your server (e.g. `auth.yourdomain.com`) 55- A reverse proxy that terminates TLS (Caddy, Traefik, or nginx) 56 57### 1. Clone and configure 58 59```bash 60git clone https://github.com/Cache8063/atauth.git 61cd atauth 62cp gateway/.env.example .env 63``` 64 65Edit `.env` -- replace every instance of `auth.yourdomain.com` with your actual domain: 66 67```env 68# These must all use your real domain 69OAUTH_CLIENT_ID=https://auth.yourdomain.com/client-metadata.json 70OAUTH_REDIRECT_URI=https://auth.yourdomain.com/auth/callback 71OIDC_ISSUER=https://auth.yourdomain.com 72WEBAUTHN_RP_ID=auth.yourdomain.com 73WEBAUTHN_ORIGIN=https://auth.yourdomain.com 74CORS_ORIGINS=https://app1.yourdomain.com,https://app2.yourdomain.com 75``` 76 77Generate and fill in the three required secrets (run the command once per value): 78 79```bash 80openssl rand -hex 32 81``` 82 83```env 84ADMIN_TOKEN=<paste-generated-value> 85OIDC_KEY_SECRET=<paste-generated-value> 86MFA_ENCRYPTION_KEY=<paste-generated-value> 87``` 88 89### 2. Start the service 90 91```bash 92docker compose up -d 93``` 94 95The 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): 96 97```caddyfile 98auth.yourdomain.com { 99 reverse_proxy localhost:3100 100} 101``` 102 103See the [Homelab Deployment Guide](docs/HOMELAB.md) for Traefik and nginx examples. 104 105### 3. Verify it's running 106 107```bash 108curl https://auth.yourdomain.com/.well-known/openid-configuration 109``` 110 111You should get a JSON document with all the OIDC endpoints. 112 113### 4. Register your first app 114 115Open `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. 116 117Save the returned **client secret** -- it is only shown once. 118 119### 5. Configure your app 120 121Point your app's OIDC settings to ATAuth's discovery URL: 122 123| Setting | Value | 124| --- | --- | 125| Discovery URL | `https://auth.yourdomain.com/.well-known/openid-configuration` | 126| Client ID | The ID you chose in the wizard | 127| Client Secret | The secret returned at registration | 128| Scopes | `openid profile` (add `email` if needed) | 129 130## Supported Apps 131 132The setup wizard includes presets for: 133 134| App | Auth Method | 135| --- | --- | 136| Audiobookshelf | OIDC (OpenID Connect) | 137| Jellyfin | OIDC (via SSO plugin) | 138| Gitea / Forgejo | OIDC (built-in) | 139| Nextcloud | OIDC (via app) | 140| Immich | OIDC (built-in) | 141| Grafana | OIDC (built-in) | 142| Wiki.js | OIDC (built-in) | 143| Portainer | OIDC (built-in) | 144| Outline | OIDC (built-in) | 145| Mealie | OIDC (built-in) | 146| Paperless-ngx | OIDC (built-in) | 147| Vaultwarden | OIDC (built-in) | 148| Miniflux | OIDC (built-in) | 149| Mattermost | OIDC (built-in) | 150| Vikunja | OIDC (built-in) | 151| Plane | OIDC (built-in) | 152| GoToSocial | OIDC (built-in) | 153| Stirling-PDF | OIDC (built-in) | 154| Tandoor Recipes | OIDC (built-in) | 155| FreshRSS | OIDC (built-in) | 156| Any web service | Forward-auth proxy (nginx `auth_request`) | 157 158## Forward-Auth Proxy 159 160For apps without OIDC support, ATAuth provides nginx `auth_request` based SSO. Enable it in `.env`: 161 162```env 163FORWARD_AUTH_ENABLED=true 164FORWARD_AUTH_SESSION_SECRET=<generate-with-openssl-rand-hex-32> 165``` 166 167Then configure nginx: 168 169```nginx 170location / { 171 auth_request /auth/verify; 172 auth_request_set $auth_did $upstream_http_x_auth_did; 173 auth_request_set $auth_handle $upstream_http_x_auth_handle; 174 proxy_set_header X-Auth-DID $auth_did; 175 proxy_set_header X-Auth-Handle $auth_handle; 176 proxy_pass http://your-app; 177} 178 179location = /auth/verify { 180 internal; 181 proxy_pass http://atauth:3100; 182 proxy_pass_request_body off; 183 proxy_set_header Content-Length ""; 184 proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 185} 186``` 187 188The admin dashboard generates these config snippets for you. 189 190## Self-Hosted PDS 191 192With a self-hosted PDS, ATAuth becomes a fully independent auth system: 193 194- Users get handles like `@alice.your-domain.com` 195- No dependency on Bluesky servers 196- Works on air-gapped networks 197- Same security model as enterprise OAuth 198 199The gateway auto-discovers the user's PDS from their handle. No special configuration needed. 200 201## Architecture 202 203| Component | Description | 204| --- | --- | 205| **Gateway** | Node.js/Express 5, TypeScript, SQLite | 206| **Identity** | AT Protocol OAuth (user's PDS) | 207| **OIDC Tokens** | ES256 signed JWTs | 208| **Proxy Cookies** | HMAC-SHA256 signed, typed | 209| **Access Control** | Deny-overrides, per-origin + global rules | 210 211## Security 212 213- No hardcoded secrets -- all sensitive config validated at startup 214- Client secrets stored as SHA-256 hashes 215- One-time flash tokens for secret display (never in URLs) 216- PKCE support (configurable per-client) 217- Constant-time comparison for all secret verification 218- HTML escaping on all server-rendered pages 219- HMAC-signed CSRF tokens on all dashboard forms 220- Rate limiting on auth endpoints 221- CSP with per-request nonces for inline scripts 222- WAF-compatible (Cloudflare Managed Ruleset + OWASP) 223 224## Documentation 225 226- [Homelab Deployment Guide](docs/HOMELAB.md) 227- [Security Policy](SECURITY.md) 228- [Changelog](CHANGELOG.md) 229 230## License 231 232MIT