export interface DevFrontAuthRedirectUris { redirectUri: string; postLogoutRedirectUri: string; popupRedirectUri: string; } export const DEVFRONT_AUTH_CALLBACK_PATH = "/auth/callback"; export function resolveDevFrontPublicOrigin( configuredOrigin: string | undefined, browserOrigin: string, ) { const trimmed = configuredOrigin?.trim(); if (!trimmed) { return browserOrigin; } try { return new URL(trimmed).origin; } catch { return browserOrigin; } } export function buildDevFrontAuthRedirectUris( publicOrigin: string, ): DevFrontAuthRedirectUris { return { redirectUri: `${publicOrigin}${DEVFRONT_AUTH_CALLBACK_PATH}`, postLogoutRedirectUri: publicOrigin, popupRedirectUri: `${publicOrigin}${DEVFRONT_AUTH_CALLBACK_PATH}`, }; } export type BrowserPkceLoginCheck = { isSecureContext?: boolean; origin?: string; cryptoSubtleAvailable?: boolean; }; const devTrustedPkceHosts = new Set([ "localhost", "127.0.0.1", "::1", "host.docker.internal", ]); function isPrivateIPv4(hostname: string) { const parts = hostname.split(".").map((part) => Number.parseInt(part, 10)); if ( parts.length !== 4 || parts.some((part) => Number.isNaN(part) || part < 0 || part > 255) ) { return false; } const [first, second] = parts; return ( first === 10 || (first === 172 && second >= 16 && second <= 31) || (first === 192 && second === 168) ); } function isDevTrustedPkceOrigin(origin: string) { try { const hostname = new URL(origin).hostname; return devTrustedPkceHosts.has(hostname) || isPrivateIPv4(hostname); } catch { return false; } } export function canStartBrowserPkceLogin({ isSecureContext = window.isSecureContext, origin = window.location.origin, cryptoSubtleAvailable = Boolean(window.crypto?.subtle), }: BrowserPkceLoginCheck = {}) { if (!cryptoSubtleAvailable) { return false; } if (isSecureContext) { return true; } return isDevTrustedPkceOrigin(origin); }