120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
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<string, string>, 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<string, string>, 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();
|
|
}
|