Skip to content

Commit 3cd5807

Browse files
committed
pick OIDC authentication dynamically
1 parent 7eb247c commit 3cd5807

2 files changed

Lines changed: 35 additions & 16 deletions

File tree

client/src/webpages/settings/SSOSettings.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ export default function SSOSettings() {
255255
</Heading>
256256

257257
<div className="flex items-center gap-2">
258-
<Text size="SM">Current method:</Text>
258+
<Text as="span" size="SM">Current method:</Text>
259259
<Badge variant={currentMethod === 'Password' ? 'secondary' : 'default'}>
260260
{currentMethod}
261261
</Badge>

server/api.ts

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ import passport from 'passport';
2929
import { MultiSamlStrategy } from '@node-saml/passport-saml';
3030
import * as oidcClient from 'openid-client';
3131

32-
function normalizeIssuerUrl(raw: string): string {
33-
return `https://${raw.replace(/^https?:\/\//, '').replace(/\/$/, '')}`;
34-
}
3532
import {
3633
makeLoginIncorrectPasswordError,
3734
makeLoginSsoRequiredError,
@@ -102,6 +99,38 @@ async function getCPUUsage() {
10299
return 1 - (endIdle - startIdle) / (endTotal - startTotal);
103100
}
104101

102+
function normalizeIssuerUrl(raw: string): string {
103+
return `https://${raw.replace(/^https?:\/\//, '').replace(/\/$/, '')}`;
104+
}
105+
106+
async function discoverOidcConfig(
107+
issuerUrl: string,
108+
clientId: string,
109+
clientSecret: string,
110+
) {
111+
const config = await oidcClient.discovery(
112+
new URL(issuerUrl),
113+
clientId,
114+
clientSecret,
115+
);
116+
117+
const supported = config.serverMetadata().token_endpoint_auth_methods_supported;
118+
119+
// Per OIDC spec, if token_endpoint_auth_methods_supported is absent the
120+
// default is ["client_secret_basic"]. If the server explicitly lists methods
121+
// and does NOT include client_secret_post, re-discover with ClientSecretBasic.
122+
if (supported && !supported.includes('client_secret_post')) {
123+
return oidcClient.discovery(
124+
new URL(issuerUrl),
125+
clientId,
126+
clientSecret,
127+
oidcClient.ClientSecretBasic(clientSecret),
128+
);
129+
}
130+
131+
return config;
132+
}
133+
105134
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
106135
const env = process.env.NODE_ENV || 'development';
107136
const sessionStore = connectPgSimple(session);
@@ -307,12 +336,7 @@ export default async function makeApiServer(deps: Dependencies) {
307336
const issuerUrl = normalizeIssuerUrl(oidcSettings.issuer_url);
308337

309338
const { API_BASE_URL } = process.env;
310-
const config = await oidcClient.discovery(
311-
new URL(issuerUrl),
312-
oidcSettings.client_id,
313-
oidcSettings.client_secret,
314-
oidcClient.ClientSecretBasic(oidcSettings.client_secret),
315-
);
339+
const config = await discoverOidcConfig(issuerUrl, oidcSettings.client_id, oidcSettings.client_secret);
316340

317341
// Reconstruct callback URL with code/state from IdP redirect.
318342
// authorizationCodeGrant needs: base = registered redirect_uri, query = code+state from IdP.
@@ -372,12 +396,7 @@ export default async function makeApiServer(deps: Dependencies) {
372396
const callbackUrl = deps.SSOService.getSSOOidcCallbackUrl();
373397
const issuerUrl = normalizeIssuerUrl(oidcSettings.issuer_url);
374398

375-
const config = await oidcClient.discovery(
376-
new URL(issuerUrl),
377-
oidcSettings.client_id,
378-
oidcSettings.client_secret,
379-
oidcClient.ClientSecretBasic(oidcSettings.client_secret),
380-
);
399+
const config = await discoverOidcConfig(issuerUrl, oidcSettings.client_id, oidcSettings.client_secret);
381400

382401
const codeVerifier = oidcClient.randomPKCECodeVerifier();
383402
const codeChallenge = await oidcClient.calculatePKCECodeChallenge(codeVerifier);

0 commit comments

Comments
 (0)