Skip to content

Commit 93b52e3

Browse files
committed
fix(sso): redact oidc client secret in providers response, add self-hosted org admin guard
1 parent b0e38f6 commit 93b52e3

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

apps/sim/app/api/auth/sso/providers/route.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createLogger } from '@sim/logger'
33
import { and, eq } from 'drizzle-orm'
44
import { type NextRequest, NextResponse } from 'next/server'
55
import { getSession } from '@/lib/auth'
6+
import { REDACTED_MARKER } from '@/lib/core/security/redaction'
67

78
const logger = createLogger('SSOProvidersRoute')
89

@@ -50,10 +51,21 @@ export async function GET(request: NextRequest) {
5051
.from(ssoProvider)
5152
.where(whereClause)
5253

53-
providers = results.map((provider) => ({
54-
...provider,
55-
providerType: (provider.samlConfig ? 'saml' : 'oidc') as 'oidc' | 'saml',
56-
}))
54+
providers = results.map((provider) => {
55+
let oidcConfig = provider.oidcConfig
56+
if (oidcConfig) {
57+
try {
58+
const parsed = JSON.parse(oidcConfig)
59+
parsed.clientSecret = REDACTED_MARKER
60+
oidcConfig = JSON.stringify(parsed)
61+
} catch {}
62+
}
63+
return {
64+
...provider,
65+
oidcConfig,
66+
providerType: (provider.samlConfig ? 'saml' : 'oidc') as 'oidc' | 'saml',
67+
}
68+
})
5769
} else {
5870
const results = await db
5971
.select({

apps/sim/app/api/auth/sso/register/route.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { db, member } from '@sim/db'
1+
import { db, member, ssoProvider } from '@sim/db'
22
import { createLogger } from '@sim/logger'
33
import { and, eq } from 'drizzle-orm'
44
import { type NextRequest, NextResponse } from 'next/server'
@@ -144,7 +144,7 @@ export async function POST(request: NextRequest) {
144144
if (providerType === 'oidc') {
145145
const {
146146
clientId,
147-
clientSecret,
147+
clientSecret: rawClientSecret,
148148
scopes,
149149
pkce,
150150
authorizationEndpoint,
@@ -153,6 +153,31 @@ export async function POST(request: NextRequest) {
153153
jwksEndpoint,
154154
} = body
155155

156+
let clientSecret = rawClientSecret
157+
if (rawClientSecret === REDACTED_MARKER) {
158+
const [existing] = await db
159+
.select({ oidcConfig: ssoProvider.oidcConfig })
160+
.from(ssoProvider)
161+
.where(eq(ssoProvider.providerId, providerId))
162+
.limit(1)
163+
if (!existing?.oidcConfig) {
164+
return NextResponse.json(
165+
{ error: 'Cannot update: existing provider not found. Re-enter your client secret.' },
166+
{ status: 400 }
167+
)
168+
}
169+
try {
170+
clientSecret = JSON.parse(existing.oidcConfig).clientSecret
171+
} catch {
172+
return NextResponse.json(
173+
{
174+
error: 'Cannot update: failed to read existing secret. Re-enter your client secret.',
175+
},
176+
{ status: 400 }
177+
)
178+
}
179+
}
180+
156181
const oidcConfig: any = {
157182
clientId,
158183
clientSecret,

apps/sim/ee/sso/components/sso-settings.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ export function SSO() {
133133
)
134134
}
135135
} else {
136+
if (activeOrganization && !canManageSSO) {
137+
return (
138+
<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-small'>
139+
Only organization owners and admins can configure Single Sign-On settings.
140+
</div>
141+
)
142+
}
136143
if (
137144
!activeOrganization &&
138145
!isLoadingProviders &&

0 commit comments

Comments
 (0)