-
-
Notifications
You must be signed in to change notification settings - Fork 36
OpenID Connect
WebSSH provides optional OIDC authorization-code authentication with PKCE. It is disabled by default and never auto-provisions a WebSSH account.
A signed-in user or administrator links an exact provider identity to an existing local account:
(normalized issuer, subject) -> WebSSH user
Email addresses and usernames are not identity keys. Optional subject and email domain allowlists are additional policy checks.
OIDC identities cannot be linked to LDAP-managed or GitHub-provisioned accounts.
- OIDC discovery and authorization-code flow.
- Exact HTTPS issuer.
- Registered WebSSH client ID.
- Client secret stored in a private read-only file.
- Exact callback URL ending in
/oidc/callback. - Claims containing a stable
suband the expected issuer.
Loopback HTTP callback is accepted only in the homelab profile. Use HTTPS for real deployments.
OIDC_ENABLED=true
OIDC_ISSUER=https://idp.example.com
OIDC_CLIENT_ID=webssh
OIDC_CLIENT_SECRET_FILE=/run/secrets/webssh_oidc_client_secret
OIDC_REDIRECT_URI=https://ssh.example.com/oidc/callback
OIDC_ALLOWED_SUBJECTS=
OIDC_ALLOWED_DOMAINS=example.com
OIDC_LOGIN_RATE_LIMIT=10 per minute
OIDC_MFA_AMR_VALUES=
OIDC_MFA_ACR_VALUES=
OIDC_PHISHING_RESISTANT_AMR_VALUES=
OIDC_PHISHING_RESISTANT_ACR_VALUES=
OIDC_STEP_UP_ACR_VALUES=
STEP_UP_MAX_AGE_SECONDS=300| Variable | Purpose |
|---|---|
OIDC_ENABLED |
Register and expose OIDC integration |
OIDC_ISSUER |
Exact provider issuer URL |
OIDC_CLIENT_ID |
Registered client ID |
OIDC_CLIENT_SECRET_FILE |
Absolute private secret-file path |
OIDC_REDIRECT_URI |
Exact registered callback |
OIDC_ALLOWED_SUBJECTS |
Optional comma-separated subject allowlist |
OIDC_ALLOWED_DOMAINS |
Optional email-domain policy |
OIDC_LOGIN_RATE_LIMIT |
Per-IP start and callback limit |
OIDC_MFA_AMR_VALUES |
Exact signed amr values treated as MFA |
OIDC_MFA_ACR_VALUES |
Exact signed acr values treated as MFA |
OIDC_PHISHING_RESISTANT_AMR_VALUES |
Exact signed amr values treated as phishing-resistant |
OIDC_PHISHING_RESISTANT_ACR_VALUES |
Exact signed acr values treated as phishing-resistant |
OIDC_STEP_UP_ACR_VALUES |
Provider-specific assurance requested for Admin Step-up |
STEP_UP_MAX_AGE_SECONDS |
Age of recent strong authentication that may be reused (60-900 seconds) |
Do not place the client secret directly in .env or Compose environment. Mount
the file read-only and restrict it to the service account.
Deployment configuration does not activate the login button by itself. After a
successful restart and readiness check, activate OIDC under Admin → Settings
→ Authentication features. If OIDC_ENABLED is false or provider startup
validation failed, the toggle is locked; selecting it cannot start or repair
OIDC from the browser.
acr and amr values are provider-specific. WebSSH never guesses their
meaning. It normalizes only bounded signed token claims and compares them to the
exact operator-configured sets above:
- a match in
OIDC_PHISHING_RESISTANT_*produces phishing-resistant assurance; - otherwise a match in
OIDC_MFA_*produces MFA assurance; - missing, malformed, conflicting, or unmapped evidence remains basic.
Configure values only from the documentation and observed signed tokens of this exact provider/app policy. A basic OIDC login cannot bypass MFA already enabled on the linked WebSSH account; WebSSH continues with an available local Passkey, TOTP, or Recovery second factor.
WebSSH does not send push notifications. Push works when the OIDC provider's
authentication policy invokes its own mobile app and returns a signed acr or
amr value that the operator mapped. This commonly requires provider-side MFA
or Conditional Access policy, app registration, and an allowed callback. Test
both a successful push and a password-only login before trusting the mapping.
For a sensitive Admin action, WebSSH can open provider reauthentication with
prompt=login, max_age=0, and OIDC_STEP_UP_ACR_VALUES. The callback must:
- belong to the currently authenticated administrator;
- return the same linked issuer and subject;
- contain a current
auth_time; - meet the requested exact signed assurance;
- consume the one-use state successfully.
Only then does WebSSH create a one-use five-minute grant bound to the exact Admin action and target. The popup returns no grant in its URL; the opener polls once and sends the grant directly in the protected request.
WebSSH creates a random state, nonce, PKCE verifier, and browser-session binding for each login. The state record is stored server-side, consumed once, and deleted before the identity is accepted. The callback validates state binding, expiry, token claims, nonce, issuer, subject policy, domain policy, account link, and account state.
Provider failures return a generic unavailable response and do not expose token or secret details.
The recommended path does not require copying a provider subject:
- Enable and activate OIDC.
- Sign in to the target WebSSH account with an existing sign-in method.
- Open Settings → Security methods → Identity provider.
- Choose Connect identity provider and complete the action-bound WebSSH confirmation.
- Sign in to the configured provider.
The callback is bound to the same browser session and local account. WebSSH stores only the provider-verified issuer and subject after the state, nonce, PKCE, allowlist, and domain checks succeed. It never searches for a matching username or email address. Repeating the flow can attach another identity from the same provider to the account.
- Enable OIDC and restart WebSSH.
- Sign in as a local administrator.
- Create or select the target local account.
- In the Admin Panel, choose the OIDC link action.
- Provide the exact provider subject.
- Complete the administrator's available Step-up method.
- Confirm the exact target username.
- Sign out and test OIDC login with the target identity.
Manual entry is intended for recovery or providers where the target user cannot complete the self-link flow. Obtain the exact subject from trusted provider documentation or operator tooling; an email address or display name is not a substitute. The mapping is unique, so a provider identity cannot be attached to multiple users.
For providers such as Tinyauth whose subject depends on the provider username and OIDC client ID, prefer the self-link flow. It captures the signed subject directly and avoids version-specific subject reconstruction.
The administrator must complete action-bound Step-up and confirm the exact target username. Unlinking removes only the mapping; the underlying local account remains.
Before unlinking the user's only practical sign-in method, verify a local password, passkey, or recovery path.
OIDC_ALLOWED_SUBJECTS restricts accepted stable subjects. It is strongest when
the provider has a manageable fixed set of users.
OIDC_ALLOWED_DOMAINS requires a matching email claim and domain. It is an
admission condition only. Linking and login still resolve identity by issuer
and subject.
| Symptom | Check |
|---|---|
| OIDC button absent |
OIDC_ENABLED and startup logs |
| Admin toggle disabled | Deployment flag or provider readiness failed; fix Compose/secret/discovery and recreate the container |
| Provider unavailable | discovery URL, DNS, TLS, secret file, egress |
| Callback rejected | exact callback, state cookie, proxy origin, system time |
| Identity not linked | Sign in locally and use Settings → Security methods → Identity provider, or verify the administrator mapping for the exact issuer and subject |
| Domain rejected | email claim and OIDC_ALLOWED_DOMAINS
|
| User rejected after link | locked, LDAP-managed, or GitHub-provisioned account state |
Operator audit events distinguish an absent mapping (unlinked), a locked
target (account_locked), and an incompatible externally managed target
(externally_managed). Browser responses remain generic so they do not disclose
account state.
Keep a local break-glass administrator. If the provider fails, local accounts continue to use their configured factors. OIDC does not introduce automatic account creation or privilege mapping.
Disabling OIDC in the Admin Panel blocks later OIDC starts without forcibly terminating existing browser or SSH sessions. Existing work reaches its normal configured lifetime. Explicit account lock, deletion, and MFA reset still revoke the target account.
Self-service linking requires no new environment variable or provider registration. The additive database migration adds only nullable account and session bindings to the short-lived OIDC state table. Existing users, OIDC identity mappings, pending login or Step-up states, and the administrator link and unlink flows remain compatible.
WebSSH documentation - Project - Issues - Discussions - Security
This Wiki is published from the versioned docs/wiki source. Please propose documentation changes through a pull request.
WebSSH Wiki
Install and operate
- Installation from Source
- Docker and Docker Compose
- Production Deployment
- Reverse Proxy and Subfolder Deployment
- Upgrading, Rollback, and FAQ
Identity and access
- Users and Account Management
- Authentication Overview
- GitHub Authentication
- LDAP and Active Directory
- OpenID Connect
- Passkeys and Recovery Codes
SSH and files
- SSH Connections and Host Keys
- Profiles, Jump Hosts, and Commands
- Terminal and Persistent tmux Sessions
- SFTP File Workspace and Transfers
- Tailscale SSH
Reference and administration