import { DEFAULT_PUBLIC_API_URL, DEFAULT_PUBLIC_FRONTEND_URL, inferApiBaseFromProjectDomain } from './project-domains'; export function normalizeBaseUrl(url: string) { return url.trim().replace(/\/+$/, ''); } export function resolveOAuthApiBase(settings: Record, fallback = DEFAULT_PUBLIC_API_URL) { const publicApi = settings.PUBLIC_API_URL?.trim(); if (publicApi) { return normalizeBaseUrl(publicApi); } const domain = settings.PROJECT_DOMAIN?.trim(); if (domain) { const inferred = inferApiBaseFromProjectDomain(domain); if (inferred) { return inferred; } if (domain.startsWith('http://') || domain.startsWith('https://')) { return normalizeBaseUrl(domain); } return `https://${domain.replace(/^\/+/, '')}/idp-api`; } return normalizeBaseUrl(fallback); } export function resolveFrontendBase(settings: Record, fallback = DEFAULT_PUBLIC_FRONTEND_URL) { const publicFrontend = settings.PUBLIC_FRONTEND_URL?.trim(); if (publicFrontend) { return normalizeBaseUrl(publicFrontend); } const domain = settings.PROJECT_DOMAIN?.trim(); if (domain) { if (domain.startsWith('http://') || domain.startsWith('https://')) { return normalizeBaseUrl(domain); } return `https://${domain.replace(/^\/+/, '')}`; } return normalizeBaseUrl(fallback); } export interface OAuthEndpoints { issuer: string; authorizationEndpoint: string; tokenEndpoint: string; userInfoEndpoint: string; openIdConfigurationUrl: string; jwksUrl: string; webIdentityUrl: string; fedcmConfigUrl: string; fedcmDiscoverUrl: string; fedcmAccountsUrl: string; fedcmIdAssertionUrl: string; widgetUrl: string; } export function buildOAuthEndpoints(apiBase: string, frontendBase?: string): OAuthEndpoints { const base = normalizeBaseUrl(apiBase); const front = normalizeBaseUrl(frontendBase ?? deriveFrontendBaseFromApi(base)); let webIdentityOrigin = front; try { webIdentityOrigin = new URL(base).origin; } catch { // keep frontend origin } return { issuer: base, authorizationEndpoint: `${base}/oauth/authorize`, tokenEndpoint: `${base}/oauth/token`, userInfoEndpoint: `${base}/oauth/userinfo`, openIdConfigurationUrl: `${base}/.well-known/openid-configuration`, jwksUrl: `${base}/.well-known/jwks.json`, webIdentityUrl: `${webIdentityOrigin}/.well-known/web-identity`, fedcmConfigUrl: `${base}/fedcm/config.json`, fedcmDiscoverUrl: `${base}/fedcm/discover.json`, fedcmAccountsUrl: `${base}/fedcm/accounts`, fedcmIdAssertionUrl: `${base}/fedcm/id_assertion`, widgetUrl: `${front}/sso-widget.js` }; } function deriveFrontendBaseFromApi(apiBase: string) { if (apiBase.endsWith('/idp-api')) { return apiBase.replace(/\/idp-api$/, ''); } return apiBase; } export function buildAuthorizeUrl( apiBase: string, params: { clientId: string; redirectUri: string; scope: string; userId?: string; state?: string; useStandardParams?: boolean } ) { const url = new URL(`${normalizeBaseUrl(apiBase)}/oauth/authorize`); if (params.useStandardParams ?? true) { url.searchParams.set('client_id', params.clientId); url.searchParams.set('redirect_uri', params.redirectUri); url.searchParams.set('response_type', 'code'); url.searchParams.set('scope', params.scope); if (params.state) url.searchParams.set('state', params.state); } else { url.searchParams.set('clientId', params.clientId); url.searchParams.set('redirectUri', params.redirectUri); url.searchParams.set('scope', params.scope); if (params.userId) url.searchParams.set('userId', params.userId); if (params.state) url.searchParams.set('state', params.state); } return url.toString(); }