docs: restructure documentation into docs/ directory, slim README, add project .mcp.json
- README.md: reduced to overview + quick start + links to docs/ - docs/architecture.md: stack, design decisions, data models, key services - docs/configuration.md: all env vars, docker-compose setup, production + security - docs/development.md: dev workflow, CI/CD, migrations, release process - docs/features.md: detailed feature breakdown + keyboard shortcuts - docs/api-keys-and-mcp.md: API key management + Fable MCP install guide - docs/sso-oauth.md: OAuth/OIDC setup (replaces docs/oauth-setup.md) - docs/changelog.md: development history from summary.md - Remove summary.md (content distributed across docs/) - Remove docs/oauth-setup.md (superseded by docs/sso-oauth.md) - .gitignore: add .mcp.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# OAuth / OIDC SSO Setup
|
||||
|
||||
Fabled Assistant supports single sign-on via any OpenID Connect provider.
|
||||
This guide covers Authentik, but the same pattern works with Keycloak, Authelia, Zitadel, etc.
|
||||
|
||||
## 1. Create the provider in Authentik
|
||||
|
||||
1. Log in to the Authentik admin UI.
|
||||
2. Go to **Applications → Providers → Create → OAuth2/OpenID Provider**.
|
||||
3. Fill in:
|
||||
- **Name:** `Fabled Assistant` (or whatever you like)
|
||||
- **Authorization flow:** your default authorization flow
|
||||
- **Client type:** `Confidential`
|
||||
- **Redirect URIs:** `https://your-fabled-domain/api/auth/oauth/callback`
|
||||
*(must match `BASE_URL` exactly, including scheme and any path prefix)*
|
||||
4. Note the generated **Client ID** and **Client Secret**.
|
||||
5. Go to **Applications → Create**, give it a name, and bind it to the provider you just created.
|
||||
6. Note the **Issuer URL** from the provider detail page — it looks like:
|
||||
```
|
||||
https://auth.example.com/application/o/fabled-assistant/
|
||||
```
|
||||
|
||||
## 2. Configure Fabled Assistant
|
||||
|
||||
Add the following environment variables to the `app` service in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
# --- Required ---
|
||||
OIDC_ISSUER: "https://auth.example.com/application/o/fabled-assistant/"
|
||||
OIDC_CLIENT_ID: "abc123xyz"
|
||||
OIDC_CLIENT_SECRET: "supersecret"
|
||||
|
||||
# --- Optional ---
|
||||
# Scopes to request (default: "openid profile email")
|
||||
# OIDC_SCOPES: "openid profile email"
|
||||
|
||||
# Disable local username/password login once SSO is working
|
||||
# LOCAL_AUTH_ENABLED: "false"
|
||||
|
||||
# Make sure BASE_URL matches the redirect URI you registered
|
||||
BASE_URL: "https://your-fabled-domain"
|
||||
```
|
||||
|
||||
> **Docker Secrets alternative:** Use `OIDC_CLIENT_SECRET_FILE` pointing to a Docker secret file instead of `OIDC_CLIENT_SECRET`.
|
||||
|
||||
Rebuild and restart:
|
||||
|
||||
```bash
|
||||
docker compose up --build -d
|
||||
```
|
||||
|
||||
## 3. Verify
|
||||
|
||||
1. Open `/api/auth/status` — it should return:
|
||||
```json
|
||||
{ "oauth_enabled": true, "local_auth_enabled": true, ... }
|
||||
```
|
||||
2. Go to the login page — you should see a **"Login with [Provider]"** button.
|
||||
3. Click it → redirected to provider → authenticate → redirected back → logged in.
|
||||
4. Check `/api/auth/me` to confirm your user record.
|
||||
|
||||
## 4. Account Linking
|
||||
|
||||
When a user logs in via OAuth for the first time, Fabled checks in this order:
|
||||
|
||||
1. **Existing OAuth sub** — returns that user immediately.
|
||||
2. **Matching email** — if a local account already exists with the same email, the OAuth identity is linked to it automatically. The user retains all their notes and tasks.
|
||||
3. **New user** — a fresh account is created. Username defaults to `preferred_username` from the provider; if taken, `_2`, `_3`, etc. is appended.
|
||||
|
||||
## 5. Disable Local Login (Optional)
|
||||
|
||||
Once everyone is using SSO:
|
||||
|
||||
```yaml
|
||||
LOCAL_AUTH_ENABLED: "false"
|
||||
```
|
||||
|
||||
The backend will reject any `POST /api/auth/login` or `POST /api/auth/register` request with a 403. The login page will only show the SSO button.
|
||||
|
||||
> **Warning:** Make sure at least one account has been linked via OAuth before disabling local login, or you will be locked out.
|
||||
|
||||
## 6. Other Providers
|
||||
|
||||
| Provider | Issuer URL format |
|
||||
|----------|------------------|
|
||||
| Authentik | `https://auth.example.com/application/o/<app-slug>/` |
|
||||
| Keycloak | `https://keycloak.example.com/realms/<realm>` |
|
||||
| Authelia | `https://auth.example.com` |
|
||||
| Zitadel | `https://your-instance.zitadel.cloud` |
|
||||
| Google | `https://accounts.google.com` |
|
||||
|
||||
The OIDC discovery endpoint (`<issuer>/.well-known/openid-configuration`) must be publicly reachable from the Fabled container (server-to-server call at login time).
|
||||
Reference in New Issue
Block a user