mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
164 lines
7.2 KiB
Markdown
164 lines
7.2 KiB
Markdown
---
|
|
description: Set up Single Sign-On with OpenID Connect. Step-by-step guides for Keycloak, Authentik, Google, and other OIDC providers.
|
|
---
|
|
|
|
# OIDC / Single Sign-On
|
|
|
|
SnapOtter supports OpenID Connect (OIDC) for single sign-on. Users can log in with an external identity provider such as Keycloak, Authentik, or Google instead of (or alongside) local username/password authentication.
|
|
|
|
## Quick start
|
|
|
|
Add these environment variables to your `docker-compose.yml`:
|
|
|
|
```yaml
|
|
services:
|
|
SnapOtter:
|
|
image: snapotter/snapotter:latest
|
|
environment:
|
|
EXTERNAL_URL: "https://photos.example.com"
|
|
OIDC_ENABLED: "true"
|
|
OIDC_ISSUER_URL: "https://auth.example.com/realms/myrealm"
|
|
OIDC_CLIENT_ID: "snapotter"
|
|
OIDC_CLIENT_SECRET: "your-secret-here"
|
|
```
|
|
|
|
The redirect URI for your provider is always:
|
|
|
|
```
|
|
${EXTERNAL_URL}/api/auth/oidc/callback
|
|
```
|
|
|
|
For example, if `EXTERNAL_URL` is `https://photos.example.com`, configure your provider's redirect URI as `https://photos.example.com/api/auth/oidc/callback`.
|
|
|
|
## Configuration reference
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OIDC_ENABLED` | `false` | Enable OIDC login. A "Sign in with SSO" button appears on the login page. |
|
|
| `OIDC_ISSUER_URL` | | Provider's issuer URL. Must support OIDC Discovery (`/.well-known/openid-configuration`). |
|
|
| `OIDC_CLIENT_ID` | | OAuth client ID registered with your provider. |
|
|
| `OIDC_CLIENT_SECRET` | | OAuth client secret. |
|
|
| `OIDC_SCOPES` | `openid profile email` | Space-separated list of scopes to request. |
|
|
| `OIDC_AUTO_CREATE_USERS` | `true` | Automatically create a local user account on first OIDC login. |
|
|
| `OIDC_DEFAULT_ROLE` | `user` | Role assigned to auto-created OIDC users. One of `admin`, `editor`, or `user`. |
|
|
| `OIDC_AUTO_LINK_USERS` | `false` | Link an OIDC identity to an existing local user if the email address matches. |
|
|
| `OIDC_PROVIDER_NAME` | | Display name shown on the login button (e.g. "Keycloak", "Google"). If empty, the button says "SSO". |
|
|
| `OIDC_CLOCK_TOLERANCE` | `30` | Clock skew tolerance in seconds for token validation. |
|
|
| `OIDC_USERNAME_CLAIM` | `preferred_username` | ID token claim used as the username for new accounts. |
|
|
| `EXTERNAL_URL` | | The public URL where SnapOtter is reachable. Required for OIDC to build the correct redirect URI. |
|
|
| `COOKIE_SECRET` | auto-generated | Secret for signing session cookies. Set this explicitly when running multiple replicas. |
|
|
|
|
## Provider guides
|
|
|
|
### Keycloak
|
|
|
|
1. Create a new realm (or use an existing one).
|
|
2. Go to **Clients** and create a new client:
|
|
- **Client ID**: `snapotter`
|
|
- **Client authentication**: On (confidential)
|
|
- **Authentication flow**: Standard flow (Authorization Code)
|
|
3. Under the client's **Settings** tab, set **Valid redirect URIs** to your callback URL (e.g. `https://photos.example.com/api/auth/oidc/callback`).
|
|
4. Copy the **Client secret** from the **Credentials** tab.
|
|
5. Set `OIDC_ISSUER_URL` to `https://keycloak.example.com/realms/your-realm`.
|
|
|
|
### Authentik
|
|
|
|
1. In the admin interface, go to **Applications > Providers** and create a new **OAuth2/OpenID Provider**.
|
|
- **Client type**: Confidential
|
|
- **Redirect URIs**: Your callback URL
|
|
- **Signing key**: Select an existing key or create one
|
|
2. Create an **Application** and link it to the provider.
|
|
3. Copy the **Client ID** and **Client Secret** from the provider settings.
|
|
4. Set `OIDC_ISSUER_URL` to `https://authentik.example.com/application/o/snapotter/` (the trailing slash matters).
|
|
|
|
### Google
|
|
|
|
1. Go to the [Google Cloud Console](https://console.cloud.google.com/).
|
|
2. Create a project (or select an existing one).
|
|
3. Navigate to **APIs & Services > OAuth consent screen** and configure it.
|
|
4. Go to **APIs & Services > Credentials** and create an **OAuth 2.0 Client ID**:
|
|
- **Application type**: Web application
|
|
- **Authorized redirect URIs**: Your callback URL
|
|
5. Copy the **Client ID** and **Client secret**.
|
|
6. Set `OIDC_ISSUER_URL` to `https://accounts.google.com`.
|
|
7. Set `OIDC_USERNAME_CLAIM` to `email` (Google does not provide `preferred_username`).
|
|
|
|
## User provisioning
|
|
|
|
### Auto-create
|
|
|
|
When `OIDC_AUTO_CREATE_USERS` is `true` (the default), a local user account is created the first time someone logs in via OIDC. The username is taken from the claim specified by `OIDC_USERNAME_CLAIM`, and the role is set to `OIDC_DEFAULT_ROLE`.
|
|
|
|
If a username collision occurs, a numeric suffix is appended (e.g. `jane` becomes `jane_2`).
|
|
|
|
### Auto-link
|
|
|
|
When `OIDC_AUTO_LINK_USERS` is `true`, SnapOtter links an OIDC identity to an existing local account if the email addresses match. This is useful when you have pre-created user accounts and want them to start using SSO without losing their data.
|
|
|
|
::: warning
|
|
Only enable auto-link if you trust your OIDC provider to verify email addresses. An unverified email could allow someone to take over another user's account.
|
|
:::
|
|
|
|
### Disabling local login
|
|
|
|
OIDC does not disable local username/password login. Both methods remain available. Admins can still log in with local credentials if the OIDC provider is unreachable.
|
|
|
|
## Self-signed certificates
|
|
|
|
If your OIDC provider uses a self-signed or private CA certificate, mount the CA bundle into the container and point `NODE_EXTRA_CA_CERTS` to it:
|
|
|
|
```yaml
|
|
services:
|
|
SnapOtter:
|
|
image: snapotter/snapotter:latest
|
|
volumes:
|
|
- ./my-ca.pem:/etc/ssl/certs/custom-ca.pem:ro
|
|
environment:
|
|
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/custom-ca.pem
|
|
OIDC_ENABLED: "true"
|
|
OIDC_ISSUER_URL: "https://auth.internal.example.com/realms/myrealm"
|
|
OIDC_CLIENT_ID: "snapotter"
|
|
OIDC_CLIENT_SECRET: "your-secret-here"
|
|
```
|
|
|
|
::: danger
|
|
Do not set `NODE_TLS_REJECT_UNAUTHORIZED=0`. This disables all TLS verification and is a security risk.
|
|
:::
|
|
|
|
## Troubleshooting
|
|
|
|
### Redirect URI mismatch
|
|
|
|
The most common error. Check for these differences between what your provider expects and what SnapOtter sends:
|
|
|
|
- `http` vs `https` - the scheme must match exactly
|
|
- Trailing slash - some providers are strict about this
|
|
- Port number - include the port if it is non-standard
|
|
- Path - must be `/api/auth/oidc/callback`
|
|
|
|
Double-check `EXTERNAL_URL`. It must match the URL users type in their browser.
|
|
|
|
### UNABLE_TO_VERIFY_LEAF_SIGNATURE
|
|
|
|
The OIDC provider is using a certificate that Node.js does not trust. See [Self-signed certificates](#self-signed-certificates) above.
|
|
|
|
### Clock skew errors
|
|
|
|
If your server clock and the OIDC provider clock are out of sync, token validation may fail. Increase `OIDC_CLOCK_TOLERANCE` (default is 30 seconds). A better fix is to run NTP on both machines.
|
|
|
|
### "OIDC provider unreachable"
|
|
|
|
SnapOtter fetches the provider's discovery document at startup and during login. Check:
|
|
|
|
- DNS resolution from inside the Docker container (`docker exec snapotter nslookup auth.example.com`)
|
|
- Firewall rules between the container and the provider
|
|
- The `OIDC_ISSUER_URL` value - it must be reachable from the server, not just from your browser
|
|
|
|
### Missing claims
|
|
|
|
If usernames or emails are empty after login, your provider may not be returning the expected claims. Verify:
|
|
|
|
- The scopes configured in `OIDC_SCOPES` include `profile` and `email`
|
|
- The provider is configured to include the claim specified in `OIDC_USERNAME_CLAIM` in the ID token
|
|
- Some providers require explicit mapper/scope configuration to release claims
|