diff --git a/ADMIN.md b/ADMIN.md index 334050f..cf671b7 100644 --- a/ADMIN.md +++ b/ADMIN.md @@ -168,12 +168,153 @@ Key settings in `backend/.env`: | `LITELLM_API_KEY` | API key for LiteLLM proxy | | `TURNSTILE_SITE_KEY` / `TURNSTILE_SECRET_KEY` | Cloudflare Turnstile bot protection | | `BBB_SERVER_URL` / `BBB_SECRET` | BigBlueButton integration for live sessions | +| `OIDC_PROVIDER_URL` | OIDC discovery URL (see SSO section below) | +| `OIDC_CLIENT_ID` | OAuth client ID from your identity provider | +| `OIDC_CLIENT_SECRET` | OAuth client secret | +| `OIDC_PROVIDER_NAME` | Display name on login button (default: "SSO") | + +## SSO / OIDC Setup + +PedsHub supports any OpenID Connect provider. When configured, a "Sign in with {provider}" button appears on the login page. Users who sign in via SSO are auto-created with a verified email — no separate registration or email verification needed. + +### How it works + +1. User clicks "Sign in with SSO" on the login page +2. Browser redirects to your identity provider (Google, Microsoft, etc.) +3. After authentication, provider redirects back to `{APP_URL}/api/auth/sso/callback` +4. PedsHub reads the `email` and `name` claims from the OIDC token +5. If no account exists, one is created automatically (role: `user`, email verified) +6. User gets a JWT and is logged in + +### Required env vars + +Add these to `backend/.env`: + +``` +OIDC_PROVIDER_URL=https://accounts.google.com +OIDC_CLIENT_ID=your-client-id-here +OIDC_CLIENT_SECRET=your-client-secret-here +OIDC_PROVIDER_NAME=Google +OIDC_SCOPES=openid email profile +``` + +Then rebuild: `docker compose build --no-cache backend celery && docker compose up -d backend celery --force-recreate` + +### SSO-only mode + +In **Admin > Settings**, toggle "SSO-Only Login" to disable password login entirely. Users will only see the SSO button. Admins can still reset passwords via CLI for emergency access. + +--- + +### Google + +1. Go to [Google Cloud Console](https://console.cloud.google.com/apis/credentials) +2. Create a new project (or select existing) +3. Go to **APIs & Services > Credentials > Create Credentials > OAuth client ID** +4. Application type: **Web application** +5. Authorized redirect URIs: `https://pedshub.com/api/auth/sso/callback` +6. Copy the Client ID and Client Secret + +``` +OIDC_PROVIDER_URL=https://accounts.google.com +OIDC_CLIENT_ID=123456789.apps.googleusercontent.com +OIDC_CLIENT_SECRET=GOCSPX-xxxxxxxx +OIDC_PROVIDER_NAME=Google +``` + +> You may need to enable the "Google+ API" or configure the OAuth consent screen first. + +### Microsoft / Azure AD + +1. Go to [Azure Portal > App registrations](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) +2. Click **New registration** +3. Name: "PedsHub", Redirect URI: `https://pedshub.com/api/auth/sso/callback` (type: Web) +4. Note the **Application (client) ID** and **Directory (tenant) ID** +5. Go to **Certificates & secrets > New client secret** — copy the value + +``` +OIDC_PROVIDER_URL=https://login.microsoftonline.com/{tenant-id}/v2.0 +OIDC_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +OIDC_CLIENT_SECRET=your-client-secret +OIDC_PROVIDER_NAME=Microsoft +``` + +Replace `{tenant-id}` with your Azure AD tenant ID. For personal Microsoft accounts, use `common` instead. + +> Under **API permissions**, ensure `openid`, `email`, and `profile` are granted. + +### Keycloak + +1. In your Keycloak admin, go to **Clients > Create client** +2. Client ID: `pedshub`, Client type: OpenID Connect +3. Valid redirect URIs: `https://pedshub.com/api/auth/sso/callback` +4. Copy the client secret from the **Credentials** tab + +``` +OIDC_PROVIDER_URL=https://keycloak.example.com/realms/your-realm +OIDC_CLIENT_ID=pedshub +OIDC_CLIENT_SECRET=your-client-secret +OIDC_PROVIDER_NAME=Keycloak +``` + +### Auth0 + +1. Go to [Auth0 Dashboard > Applications](https://manage.auth0.com/#/applications) +2. Create a **Regular Web Application** +3. In Settings, add Allowed Callback URL: `https://pedshub.com/api/auth/sso/callback` +4. Note the Domain, Client ID, and Client Secret + +``` +OIDC_PROVIDER_URL=https://your-tenant.auth0.com +OIDC_CLIENT_ID=your-client-id +OIDC_CLIENT_SECRET=your-client-secret +OIDC_PROVIDER_NAME=Auth0 +``` + +### Authentik + +1. In Authentik admin, go to **Applications > Providers > Create OAuth2/OpenID Provider** +2. Redirect URI: `https://pedshub.com/api/auth/sso/callback` +3. Create an Application linked to this provider + +``` +OIDC_PROVIDER_URL=https://auth.example.com/application/o/pedshub +OIDC_CLIENT_ID=your-client-id +OIDC_CLIENT_SECRET=your-client-secret +OIDC_PROVIDER_NAME=Authentik +``` + +### Troubleshooting SSO + +**"SSO login failed" after redirect:** +- Check that `APP_URL` in `.env` matches your actual domain (with https) +- Verify the redirect URI in your provider matches exactly: `{APP_URL}/api/auth/sso/callback` +- Check backend logs: `docker compose logs backend --tail=30 | grep -i "sso\|oidc\|oauth"` + +**User created but wrong name:** +- The app reads `name` from the OIDC token, falling back to `preferred_username`, then the email prefix +- Some providers require the `profile` scope to include the name — make sure `OIDC_SCOPES=openid email profile` + +**Existing user can't SSO:** +- If a user registered with email/password and later tries SSO with the same email, it works — SSO login finds the existing account by email and logs them in (doesn't create a duplicate) + +**SSO-only mode lockout:** +- If SSO breaks while in SSO-only mode, use the CLI to disable it: + ```bash + docker compose exec backend python3 -c " + import redis; r = redis.from_url('redis://redis:6379/0', decode_responses=True) + r.set('settings:sso_only', 'false') + print('SSO-only mode disabled') + " + ``` + +--- ## Security Notes - Passwords are hashed with **bcrypt** (one-way, irreversible) -- Registration checks passwords against **Have I Been Pwned** breach database (warns, doesn't block) -- Only the first 5 characters of the SHA-1 hash are sent to HIBP (k-anonymity) - JWT tokens auto-refresh via sliding expiration (12h age or <1h remaining) - Rate limiting on login (10 attempts per IP per 15 min) via Redis -- Email verification required for new accounts +- Email verification required for new accounts (SSO users are auto-verified) +- Quiz reminders skip deleted quizzes and course quizzes +- Users can opt out of reminders in Settings > Notifications