theta42/proxy fronts an arbitrary number of hosts behind SSO, each with its own callback URL (https://<host>/__proxy_auth/callback) — proxy's own code comment already assumed "a wildcard redirect URI covers all", but no wildcard matching existed here, so every proxied host's callback had to be registered on the shared OAuth client individually or /oauth/authorize would reject it with InvalidRedirectURI. Add `*` (one hostname label) / `**` (any number of labels) wildcard support to redirect_uri matching, e.g. `https://**.example.com/__proxy_auth/callback` now covers every host proxy fronts under example.com. Exact matches still work exactly as before. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.2 KiB
layout, title
| layout | title |
|---|---|
| default | OAuth / OIDC |
OAuth 2.0 / OpenID Connect
SSO Manager is an OpenID Connect / OAuth 2.0 provider: it issues its own access, refresh, and ID tokens that your apps can consume to authenticate users and authorize API calls. It also runs a full OpenLDAP directory, so it can be both your SSO and your user directory at once.
Discovery
The provider publishes a standards-compliant discovery document:
GET https://<sso-host>/.well-known/openid-configuration
It advertises the issuer, authorization_endpoint, token_endpoint,
userinfo_endpoint, end_session_endpoint, supported scopes, and token
lifetimes. OIDC clients (e.g. the theta42/proxy) can read their endpoint URLs
from here rather than configuring each one.
The issuer advertised is conf.oauth.issuer — set it to the browser-facing
HTTPS URL the SSO is served at (e.g. https://sso.example.com), either in
conf/secrets.js or via app_oauth__issuer / OAUTH_ISSUER.
OAuth clients
An OAuth client represents an app that authenticates against the SSO. Each has:
client_id(UUID) +client_secret(bcrypt-hashed; the raw secret is shown once when the client is created or rotated — save it immediately).name,description,created_by(the admin uid that created it).redirect_uris— allowed callback URLs. Each entry matches exactly, or may use*(one hostname label) /**(any number of labels) as a wildcard — e.g.https://*.example.com/__proxy_auth/callbackcovers every host theta42/proxy fronts underexample.com, so you don't have to register each proxied host's callback individually.scopes— requested scopes (defaultopenid profile email groups).allowed_groups— restrict the client to members of specific SSO groups (empty = any valid user).token_lifetime—access_token/refresh_tokenlifetimes (seconds).
Managing clients
Clients are managed from the web UI (as a member of the app_sso_oauth_admin
group) or the HTTP API at /api/oauth/client (auth via the auth-token header
from a login):
| Method | Path | Action |
|---|---|---|
GET |
/api/oauth/client |
list clients |
POST |
/api/oauth/client |
create a client (returns the raw client_secret once) |
GET |
/api/oauth/client/:id |
get one |
PUT |
/api/oauth/client/:id |
update redirect URIs / scopes / groups |
DELETE |
/api/oauth/client/:id |
delete |
POST |
/api/oauth/client/:id/rotate |
rotate the secret (returns the new raw secret once) |
All client-management endpoints are gated by the
app_sso_oauth_admingroup.
Scopes
| Scope | Claims / access |
|---|---|
openid |
OIDC ID token + discovery |
profile |
preferred_username, display name, etc. |
email |
the user's mail |
groups |
the user's group memberships (the groups claim) |
The groups claim is what relying parties (e.g. the proxy's
app_auth__adminGroups) use to map group membership to roles.
Token lifetimes
Defaults (overridable per-client via token_lifetime, or globally via
app_oauth__token_lifetime__access_token /
app_oauth__token_lifetime__refresh_token):
- access token: 3600s (1 hour)
- refresh token: 2592000s (30 days)
Admin gating
SSO admin actions are gated by LDAP group membership (checked via the group's
member list, not memberOf on the user):
app_sso_admin— full admin (users, groups, settings).app_sso_oauth_admin— OAuth client management.app_sso_invite— invitation management.
The bootstrap in theta-env creates your
first admin and adds them to app_sso_admin + app_sso_oauth_admin
automatically; for a standalone install, add the admin's DN to those groups
manually (or via ops/ldap-setup.sh).
JWT signing
Tokens are signed with conf.oauth.jwtSecret (app_oauth__jwtSecret /
JWT_SECRET). Persist this secret — if it changes, every issued token
stops validating. The all-in-one Docker image auto-generates one if none is set,
but that generated value does not survive container recreation unless you
persist it (set JWT_SECRET in your .env).