From 9f7216565b3a33fc1dd45e4b76cfd393093bf501 Mon Sep 17 00:00:00 2001 From: hzhang Date: Mon, 18 May 2026 09:47:28 +0100 Subject: [PATCH] fix(center): graceful 4xx when OIDC issuer/token endpoint unreachable Wrap discovery + token-exchange fetch in try/catch so a DNS/network failure returns BadRequest/Unauthorized instead of a bare 500. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/auth/oidc.service.ts | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/auth/oidc.service.ts b/src/auth/oidc.service.ts index ea8e50c..8c9cc83 100644 --- a/src/auth/oidc.service.ts +++ b/src/auth/oidc.service.ts @@ -62,7 +62,12 @@ export class OidcService { return this.discoveryCache.doc; } const url = issuer.replace(/\/$/, '') + '/.well-known/openid-configuration'; - const res = await fetch(url); + let res: Response; + try { + res = await fetch(url); + } catch { + throw new BadRequestException('oidc: issuer unreachable (discovery failed)'); + } if (!res.ok) throw new BadRequestException(`oidc discovery failed: ${res.status}`); const doc = (await res.json()) as Discovery; if (!doc.authorization_endpoint || !doc.token_endpoint) { @@ -120,11 +125,16 @@ export class OidcService { client_secret: c.clientSecret, code_verifier: st.cv, }); - const tokRes = await fetch(doc.token_endpoint, { - method: 'POST', - headers: { 'content-type': 'application/x-www-form-urlencoded', accept: 'application/json' }, - body: body.toString(), - }); + let tokRes: Response; + try { + tokRes = await fetch(doc.token_endpoint, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded', accept: 'application/json' }, + body: body.toString(), + }); + } catch { + throw new UnauthorizedException('oidc: token endpoint unreachable'); + } if (!tokRes.ok) { throw new UnauthorizedException(`oidc: token exchange failed (${tokRes.status})`); }