mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-05 15:23:27 +00:00
When offline_access scope is configured, Pulse now stores and uses OIDC refresh tokens to automatically extend sessions. Sessions remain valid as long as the IdP allows token refresh (typically 30-90 days). Changes: - Store OIDC tokens (refresh token, expiry, issuer) alongside sessions - Automatically refresh tokens when access token nears expiry - Invalidate session if IdP revokes access (forces re-login) - Add background token refresh with concurrency protection - Persist OIDC tokens across restarts Related to #854
86 lines
4.2 KiB
Markdown
86 lines
4.2 KiB
Markdown
# 🔐 OIDC Single Sign-On
|
|
|
|
Enable Single Sign-On (SSO) with providers like Authentik, Keycloak, Okta, and Azure AD.
|
|
|
|
## 🚀 Quick Start
|
|
|
|
1. **Configure Provider**: Create an OIDC application in your IdP.
|
|
* **Redirect URI**: `https://<your-pulse-domain>/api/oidc/callback`
|
|
* **Scopes**: `openid`, `profile`, `email`
|
|
2. **Enable in Pulse**: Go to **Settings → Security → Single sign-on (OIDC)**.
|
|
3. **Enter Details**:
|
|
* **Issuer URL**: The base URL of your IdP (e.g., `https://auth.example.com/application/o/pulse/`).
|
|
* **Client ID & Secret**: From your IdP.
|
|
4. **Save**: The login page will now show a "Continue with Single Sign-On" button.
|
|
|
|
> **Tip**: To hide the username/password form and only show the SSO button, set `PULSE_AUTH_HIDE_LOCAL_LOGIN=true` in your environment. You can still access the local login by appending `?show_local=true` to the URL (e.g., `https://your-pulse-instance/?show_local=true`).
|
|
|
|
## ⚙️ Configuration
|
|
|
|
| Setting | Description |
|
|
| :--- | :--- |
|
|
| **Issuer URL** | The OIDC provider's issuer URL. Must match the `iss` claim in tokens. |
|
|
| **Client ID** | The application ID from your provider. |
|
|
| **Client Secret** | The application secret. |
|
|
| **Redirect URL** | Auto-detected. Override only if running behind a complex proxy setup. |
|
|
| **Scopes** | Space-separated scopes. Default: `openid profile email`. |
|
|
| **Claim Mapping** | Map `email`, `username`, and `groups` to specific token claims. |
|
|
|
|
### Access Control
|
|
Restrict access to specific users or groups:
|
|
* **Allowed Groups**: Only users in these groups can login. Requires the `groups` scope/claim.
|
|
* **Allowed Domains**: Restrict to specific email domains (e.g., `example.com`).
|
|
* **Allowed Emails**: Allow specific email addresses.
|
|
|
|
### Long-Lived Sessions with `offline_access`
|
|
For persistent sessions that don't require frequent re-authentication:
|
|
|
|
1. **Add `offline_access` scope**: Include `offline_access` in your OIDC scopes (e.g., `openid profile email offline_access`).
|
|
2. **Configure your IdP**: Ensure your identity provider issues refresh tokens when `offline_access` is requested.
|
|
|
|
**How it works:**
|
|
- When you login with `offline_access`, Pulse stores the refresh token alongside your session.
|
|
- When your access token expires, Pulse automatically refreshes it using the stored refresh token.
|
|
- Your session remains valid as long as the refresh token is valid (typically 30-90 days depending on your IdP).
|
|
- If the IdP revokes access (user disabled, token revoked), Pulse detects this on the next refresh attempt and logs you out.
|
|
|
|
**Security considerations:**
|
|
- Refresh tokens are stored encrypted at rest.
|
|
- If the IdP configuration changes, existing sessions with mismatched issuers are automatically invalidated.
|
|
- Failed refresh attempts immediately invalidate the session.
|
|
|
|
## 📚 Provider Examples
|
|
|
|
### Authentik
|
|
* **Type**: OAuth2/OpenID (Confidential)
|
|
* **Redirect URI**: `https://pulse.example.com/api/oidc/callback`
|
|
* **Signing Key**: Must use **RS256** (create a certificate/key pair if needed).
|
|
* **Issuer URL**: `https://auth.example.com/application/o/pulse/`
|
|
|
|
### Keycloak
|
|
* **Client ID**: `pulse`
|
|
* **Access Type**: Confidential
|
|
* **Valid Redirect URIs**: `https://pulse.example.com/api/oidc/callback`
|
|
* **Issuer URL**: `https://keycloak.example.com/realms/myrealm`
|
|
|
|
### Azure AD
|
|
* **Redirect URI**: `https://pulse.example.com/api/oidc/callback` (Web)
|
|
* **Issuer URL**: `https://login.microsoftonline.com/<tenant-id>/v2.0`
|
|
* **Note**: Enable "ID tokens" in Authentication settings.
|
|
|
|
## 🔧 Troubleshooting
|
|
|
|
| Issue | Solution |
|
|
| :--- | :--- |
|
|
| **`invalid_id_token`** | Issuer URL mismatch. Check logs (`LOG_LEVEL=debug`) to see the expected vs. received issuer. |
|
|
| **`unexpected signature algorithm "HS256"`** | Your IdP is signing with HS256. Configure it to use **RS256**. |
|
|
| **Redirect Loop** | Check `X-Forwarded-Proto` header (must be `https`) and cookie settings. |
|
|
| **Self-Signed Certs** | Mount your CA bundle to `/etc/ssl/certs/oidc-ca.pem` and set `OIDC_CA_BUNDLE`. |
|
|
|
|
### Debugging
|
|
Enable debug logs to trace the OIDC flow:
|
|
```bash
|
|
export LOG_LEVEL=debug
|
|
# Restart Pulse
|
|
```
|
|
Logs will show discovery, token exchange, and claim parsing details.
|