diff --git a/.env.example b/.env.example index a79937c2..4e220d61 100644 --- a/.env.example +++ b/.env.example @@ -74,3 +74,25 @@ NUXT_PUBLIC_SITE_URL=http://localhost:3000 # POSTHOG_PUBLIC_KEY=phc_... # EU data center (default). Use https://us.i.posthog.com for US. # POSTHOG_HOST=https://eu.i.posthog.com + +# ─── Optional: OIDC SSO (Keycloak, Authentik, Authelia, Okta, etc.) ────────── +# Enable Single Sign-On via any OIDC-compliant identity provider. +# All three variables (CLIENT_ID, CLIENT_SECRET, DISCOVERY_URL) must be set to activate SSO. +# When configured, a "Sign in with SSO" button appears on the login page. + +# OIDC client ID — from your identity provider's client/application settings +# OIDC_CLIENT_ID=reqcore + +# OIDC client secret — from your identity provider's credentials tab +# OIDC_CLIENT_SECRET=your-client-secret-here + +# OIDC discovery URL — the .well-known/openid-configuration endpoint +# Keycloak: https://keycloak.example.com/realms/YOUR_REALM/.well-known/openid-configuration +# Authentik: https://authentik.example.com/application/o/YOUR_APP/.well-known/openid-configuration +# Authelia: https://authelia.example.com/.well-known/openid-configuration +# Okta: https://YOUR_ORG.okta.com/.well-known/openid-configuration +# Azure AD: https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0/.well-known/openid-configuration +# OIDC_DISCOVERY_URL=https://keycloak.example.com/realms/master/.well-known/openid-configuration + +# Display name for the SSO button (default: "SSO") +# OIDC_PROVIDER_NAME=Company SSO diff --git a/SELF-HOSTING.md b/SELF-HOSTING.md index 20c522fb..1f0f8a96 100644 --- a/SELF-HOSTING.md +++ b/SELF-HOSTING.md @@ -450,6 +450,68 @@ sudo dpkg-reconfigure -plow unattended-upgrades --- +## OIDC Single Sign-On (SSO) + +Reqcore supports Single Sign-On via any OIDC-compliant identity provider — Keycloak, Authentik, Authelia, Okta, Azure AD, and more. When configured, a "Sign in with SSO" button appears on the login and registration pages. + +### Why SSO? + +- **Centralized identity** — users sign in once across all internal tools +- **Zero-friction onboarding** — new hires get instant access, leavers are cut off centrally +- **Enterprise security** — MFA, session policies, and brute-force protection managed in one place + +### Setup + +**1. Create an OIDC client in your identity provider:** + +| Setting | Value | +|---|---| +| Client type | OpenID Connect (confidential) | +| Client ID | Any name (e.g., `reqcore`) | +| Client authentication | ON (confidential/secret) | +| Valid redirect URI | `https://your-reqcore-domain.com/api/auth/oauth2/callback/oidc` | +| Valid post-logout redirect URI | `https://your-reqcore-domain.com/*` | +| Scopes | `openid`, `email`, `profile` | + +**2. Set environment variables:** + +```bash +# All three are required to activate SSO +OIDC_CLIENT_ID=reqcore +OIDC_CLIENT_SECRET=your-client-secret-from-provider +OIDC_DISCOVERY_URL=https://keycloak.example.com/realms/master/.well-known/openid-configuration + +# Optional: customize the button label (default: "SSO") +OIDC_PROVIDER_NAME=Company SSO +``` + +**3. Restart Reqcore:** + +```bash +docker compose down && docker compose up -d +``` + +The SSO button appears automatically on the sign-in and sign-up pages. + +### Provider-Specific Discovery URLs + +| Provider | Discovery URL format | +|---|---| +| Keycloak | `https://keycloak.example.com/realms/YOUR_REALM/.well-known/openid-configuration` | +| Authentik | `https://authentik.example.com/application/o/YOUR_APP/.well-known/openid-configuration` | +| Authelia | `https://authelia.example.com/.well-known/openid-configuration` | +| Okta | `https://YOUR_ORG.okta.com/.well-known/openid-configuration` | +| Azure AD | `https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0/.well-known/openid-configuration` | + +### Security + +- **PKCE** (Proof Key for Code Exchange) is enabled by default for protection against authorization code interception +- **Issuer validation** (RFC 9207) is enforced to prevent OAuth mix-up attacks +- **OIDC discovery** automatically fetches and validates all provider endpoints +- SSO is **completely opt-in** — it has zero impact when the environment variables are not set + +--- + ## Monitoring & Health Checks ### Built-in System Health Dashboard diff --git a/app/components/SettingsMobileNav.vue b/app/components/SettingsMobileNav.vue index f98e04b2..96b0227c 100644 --- a/app/components/SettingsMobileNav.vue +++ b/app/components/SettingsMobileNav.vue @@ -1,6 +1,6 @@ - - +
+ diff --git a/app/pages/auth/sign-up.vue b/app/pages/auth/sign-up.vue index 0161341f..5757981f 100644 --- a/app/pages/auth/sign-up.vue +++ b/app/pages/auth/sign-up.vue @@ -1,149 +1,235 @@ - + - diff --git a/app/pages/dashboard/settings/sso.vue b/app/pages/dashboard/settings/sso.vue new file mode 100644 index 00000000..a1108bf4 --- /dev/null +++ b/app/pages/dashboard/settings/sso.vue @@ -0,0 +1,500 @@ + + + ++ Allow your team to sign in with their corporate identity provider (Okta, Azure AD, Google Workspace, etc.). +
++ {{ formSuccess }} +
+ ++ {{ formError }} +
+ +
+
+
+ Redirect URI (add this in your IdP): +
+
+ {{ getCallbackUrl(provider.providerId) }}
+
+
+ + Connect your corporate identity provider so your team can sign in with their work accounts — no separate passwords needed. +
+ +{{ `${siteOrigin}/api/auth/sso/callback/{provider-id}` }}You register your company's identity provider (IdP) — Okta, Azure AD, Google Workspace, or any OIDC-compliant provider.
+Team members visit the sign-in page and enter their work email. Reqcore detects the email domain and redirects to your IdP.
+After authenticating with the IdP, users are automatically provisioned into your organization as members — no invitation needed.
+