{"record":{"id":"c3c59b065430761a","repo":"different-ai/openwork","slug":"manual-oidc-configuration-requires-authorization","errorCode":null,"errorMessage":"Manual OIDC configuration requires authorization, token, and JWKS endpoints.","messagePattern":"Manual OIDC configuration requires authorization, token, and JWKS endpoints\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/sso.ts","lineNumber":104,"sourceCode":"    const url = new URL(issuer)\n    return url.hostname === \"127.0.0.1\" || url.hostname === \"localhost\"\n  } catch {\n    return false\n  }\n}\n\nfunction getOidcDiscoveryUrl(issuer: string) {\n  return `${issuer.replace(/\\/$/, \"\")}/.well-known/openid-configuration`\n}\n\nfunction normalizeIssuer(value: string) {\n  return value.replace(/\\/$/, \"\")\n}\n\nasync function resolveOidcEndpoints(input: OidcRegistrationInput) {\n  if (input.skipDiscovery) {\n    if (!input.authorizationEndpoint || !input.tokenEndpoint || !input.jwksEndpoint) {\n      throw new Error(\"Manual OIDC configuration requires authorization, token, and JWKS endpoints.\")\n    }\n\n    return {\n      skipDiscovery: true,\n      authorizationEndpoint: input.authorizationEndpoint,\n      tokenEndpoint: input.tokenEndpoint,\n      jwksEndpoint: input.jwksEndpoint,\n      userInfoEndpoint: input.userInfoEndpoint ?? undefined,\n      tokenEndpointAuthentication: input.tokenEndpointAuthentication ?? undefined,\n    }\n  }\n\n  const response = await fetch(getOidcDiscoveryUrl(input.issuer), {\n    headers: { accept: \"application/json\" },\n    signal: AbortSignal.timeout(10_000),\n  })\n  if (!response.ok) {\n    throw new Error(`OIDC discovery failed with ${response.status}. Enter manual OIDC endpoints or enable skip discovery.`)","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/sso.ts#L86-L122","documentation":"resolveOidcEndpoints supports manual OIDC configuration when discovery is skipped. In skipDiscovery mode all three endpoints — authorizationEndpoint, tokenEndpoint, and jwksEndpoint — are mandatory; any missing one throws this Error.","triggerScenarios":"Registering an OIDC SSO connection with skipDiscovery: true while omitting one or more of authorizationEndpoint, tokenEndpoint, or jwksEndpoint in OidcRegistrationInput.","commonSituations":"Admin pasted only the issuer and authorization URL assuming discovery; JWKS URL forgotten; provider docs give discovery only and admin toggled skipDiscovery unnecessarily; partial copy/paste of endpoint config.","solutions":["Provide all three endpoints (authorization, token, JWKS) in the manual OIDC configuration","If your provider exposes /.well-known/openid-configuration, set skipDiscovery: false and supply only the issuer instead","Verify each endpoint URL is absolute and correct for your IdP (Auth0, Okta, Entra ID, Keycloak)"],"exampleFix":"// before\n{ issuer: 'https://idp.example.com', skipDiscovery: true, authorizationEndpoint: 'https://idp.example.com/authorize' }\n// after\n{ issuer: 'https://idp.example.com', skipDiscovery: true, authorizationEndpoint: 'https://idp.example.com/authorize', tokenEndpoint: 'https://idp.example.com/token', jwksEndpoint: 'https://idp.example.com/.well-known/jwks.json' }","handlingStrategy":"validation","validationCode":"const missing = [\n  input.authorizationEndpoint ? null : 'authorizationEndpoint',\n  input.tokenEndpoint ? null : 'tokenEndpoint',\n  input.jwksEndpoint ? null : 'jwksEndpoint',\n].filter(Boolean)\nif (input.skipDiscovery && missing.length > 0) throw new Error(`Manual OIDC configuration missing: ${missing.join(', ')}`)","typeGuard":"function isCompleteManualOidcConfig(i: Partial<OidcRegistrationInput> & { skipDiscovery?: boolean }): i is OidcRegistrationInput {\n  return !i.skipDiscovery || Boolean(i.authorizationEndpoint && i.tokenEndpoint && i.jwksEndpoint)\n}","tryCatchPattern":"try {\n  await resolveOidcEndpoints(input)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Manual OIDC configuration requires')) {\n    // return 400 with which endpoints are missing\n  } else throw e\n}","preventionTips":["Collect all three endpoint fields together in the SSO admin UI when discovery is disabled","Default to discovery (skipDiscovery: false) unless the IdP lacks a well-known document","Validate endpoint URLs are absolute https URLs before saving"],"tags":["oidc","sso","configuration","validation"],"backgroundTag":"missing-oidc-endpoint","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}