Skip to content

Commit 18f9713

Browse files
os-zhuangclaude
andauthored
feat(auth): surface "SSO Providers" in the Setup nav when SSO is enabled (ADR-0024 / cloud#551) (#2389)
The sys_sso_provider admin object (register/list/delete external OIDC IdPs) had no nav entry — reachable only by direct URL. AuthPlugin now contributes an "SSO Providers" entry into the Setup app's Access Control group, gated on AuthManager.isSsoWired() (captures self-host OS_SSO_ENABLED + cloud per-env planAllowsSso via plugins.sso) so it never renders when the RP is off. Owning-plugin-contributes pattern (ADR-0029 K2), mirrors plugin-security. isSsoWired() made public for the gate. Verified: entry appears under Setup → Access Control when SSO on; the register form renders all fields (incl. discoveryEndpoint/scopes/mapping) and posts to the bridge (200). (The list view shows empty for now — a pre-existing platform behavior shared by all better-auth-managed objects, e.g. OAuth Applications / Identity Links already in nav read 0 via the data API; separate follow-up.) Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 90bce88 commit 18f9713

3 files changed

Lines changed: 39 additions & 1 deletion

File tree

.changeset/adr-0024-sso-nav.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@objectstack/plugin-auth': patch
3+
---
4+
5+
Auth: surface "SSO Providers" in the Setup app nav when SSO is enabled (ADR-0024 / cloud#551)
6+
7+
The `sys_sso_provider` admin object (register / list / delete external OIDC IdPs) had no navigation entry, so an admin could only reach it by direct URL. `AuthPlugin` now contributes an **"SSO Providers"** entry into the Setup app's **Access Control** group — but only when the external-IdP RP is wired (`AuthManager.isSsoWired()`, which captures both self-host `OS_SSO_ENABLED` and the cloud per-env `planAllowsSso` arriving via `plugins.sso`). Owning-plugin-contributes pattern (ADR-0029 K2), mirroring `plugin-security`. `isSsoWired()` is made public for this gate.

packages/plugins/plugin-auth/src/auth-manager.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1981,8 +1981,11 @@ export class AuthManager {
19811981
* in `buildPlugins()` (`ssoFromEnv ?? pluginConfig.sso ?? false`) so the
19821982
* advertised capability can never disagree with the actual `/sign-in/sso`
19831983
* route. `OS_SSO_ENABLED` (when set) wins over the config-file setting.
1984+
* Public so `AuthPlugin` can gate the Setup-nav "SSO Providers" entry on it
1985+
* (captures both self-host `OS_SSO_ENABLED` and the cloud per-env
1986+
* `planAllowsSso` config, since that arrives via `plugins.sso`).
19841987
*/
1985-
private isSsoWired(): boolean {
1988+
public isSsoWired(): boolean {
19861989
const ssoEnv = (globalThis as any)?.process?.env?.OS_SSO_ENABLED;
19871990
const ssoFromEnv = ssoEnv != null ? String(ssoEnv).toLowerCase() === 'true' : undefined;
19881991
return ssoFromEnv ?? (this.config.plugins as any)?.sso ?? false;

packages/plugins/plugin-auth/src/auth-plugin.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,34 @@ export class AuthPlugin implements Plugin {
200200
dashboards: [SystemOverviewDashboard],
201201
// ADR-0021 — datasets backing the System Overview dashboard's widgets.
202202
datasets: SystemOverviewDatasets,
203+
// ADR-0024 / cloud#551 — surface "SSO Providers" (sys_sso_provider) in the
204+
// Setup app's Access Control group, but ONLY when the external-IdP RP is
205+
// wired (self-host `OS_SSO_ENABLED`, or the cloud per-env `planAllowsSso`
206+
// arriving via `plugins.sso`). Without the gate the entry would render an
207+
// empty list + a "Register" button whose endpoint 404s when SSO is off.
208+
// Owning-plugin-contributes pattern (ADR-0029 K2), mirroring plugin-security.
209+
...(this.authManager.isSsoWired()
210+
? {
211+
navigationContributions: [
212+
{
213+
app: 'setup',
214+
group: 'group_access_control',
215+
// After Roles/Permission-Sets (100) and Sharing (200), near API Keys (300).
216+
priority: 250,
217+
items: [
218+
{
219+
id: 'nav_sso_providers',
220+
type: 'object',
221+
label: 'SSO Providers',
222+
objectName: 'sys_sso_provider',
223+
icon: 'log-in',
224+
requiredPermissions: ['manage_platform_settings'],
225+
},
226+
],
227+
},
228+
],
229+
}
230+
: {}),
203231
});
204232

205233
ctx.logger.info('Auth Plugin initialized successfully');

0 commit comments

Comments
 (0)