@oxyhq/services
Version:
156 lines (147 loc) • 4.87 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isWebBrowser = isWebBrowser;
exports.useWebSSO = useWebSSO;
var _react = require("react");
/**
* Web SSO Hook
*
* Handles cross-domain SSO for web apps using FedCM (Federated Credential Management).
*
* FedCM is the modern, privacy-preserving standard for cross-domain identity federation.
* It works across completely different TLDs (alia.onl, mention.earth, homiio.com, etc.)
* without relying on third-party cookies.
*
* For browsers without FedCM support, users will need to click a sign-in button
* which triggers a popup-based authentication flow.
*
* This is called automatically by OxyContext on web platforms.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API
*/
/**
* Check if we're running in a web browser environment (not React Native)
*/
function isWebBrowser() {
return typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.documentElement !== 'undefined';
}
/**
* Check if we're on the identity provider domain (where FedCM would authenticate against itself)
* Only auth.oxy.so is the IdP - accounts.oxy.so is a client app like any other
*/
function isIdentityProvider() {
if (!isWebBrowser()) return false;
const hostname = window.location.hostname;
return hostname === 'auth.oxy.so';
}
/**
* Hook for automatic cross-domain web SSO
*
* Uses FedCM (Federated Credential Management) - the modern browser-native
* identity federation API. This is the same technology that powers
* Google's cross-domain SSO (YouTube, Gmail, Maps, etc.).
*
* Key benefits:
* - Works across different TLDs (alia.onl ↔ mention.earth ↔ homiio.com)
* - No third-party cookies required
* - Privacy-preserving (browser mediates identity, IdP can't track)
* - Automatic silent sign-in after initial authentication
*
* For browsers without FedCM (Firefox, older browsers), automatic SSO
* is not possible. Users will see a sign-in button instead.
*/
function useWebSSO({
oxyServices,
onSessionFound,
onSSOUnavailable,
onError,
enabled = true
}) {
const isCheckingRef = (0, _react.useRef)(false);
const hasCheckedRef = (0, _react.useRef)(false);
// Check FedCM support once
const fedCMSupported = isWebBrowser() && oxyServices.isFedCMSupported?.();
const checkSSO = (0, _react.useCallback)(async () => {
if (!isWebBrowser() || isCheckingRef.current) {
return null;
}
// Don't use FedCM on the auth domain itself - it would authenticate against itself
if (isIdentityProvider()) {
onSSOUnavailable?.();
return null;
}
// FedCM is the only reliable cross-domain SSO mechanism
if (!fedCMSupported) {
onSSOUnavailable?.();
return null;
}
isCheckingRef.current = true;
try {
const session = await oxyServices.silentSignInWithFedCM?.();
if (session) {
await onSessionFound(session);
return session;
}
onSSOUnavailable?.();
return null;
} catch (error) {
onSSOUnavailable?.();
onError?.(error instanceof Error ? error : new Error(String(error)));
return null;
} finally {
isCheckingRef.current = false;
}
}, [oxyServices, onSessionFound, onSSOUnavailable, onError, fedCMSupported]);
/**
* Trigger interactive FedCM sign-in
* This shows the browser's native "Sign in with Oxy" prompt.
* Use this when silent mediation fails (user hasn't previously consented).
*/
const signInWithFedCM = (0, _react.useCallback)(async () => {
if (!isWebBrowser() || isCheckingRef.current) {
return null;
}
if (!fedCMSupported) {
onError?.(new Error('FedCM is not supported in this browser'));
return null;
}
isCheckingRef.current = true;
try {
const session = await oxyServices.signInWithFedCM?.();
if (session) {
await onSessionFound(session);
return session;
}
return null;
} catch (error) {
onError?.(error instanceof Error ? error : new Error(String(error)));
return null;
} finally {
isCheckingRef.current = false;
}
}, [oxyServices, onSessionFound, onError, fedCMSupported]);
// Auto-check SSO on mount (web only, FedCM only, not on auth domain)
(0, _react.useEffect)(() => {
if (!enabled || !isWebBrowser() || hasCheckedRef.current || isIdentityProvider()) {
if (isIdentityProvider()) {
onSSOUnavailable?.();
}
return;
}
hasCheckedRef.current = true;
if (fedCMSupported) {
checkSSO();
} else {
onSSOUnavailable?.();
}
}, [enabled, checkSSO, fedCMSupported, onSSOUnavailable]);
return {
checkSSO,
signInWithFedCM,
isChecking: isCheckingRef.current,
isFedCMSupported: fedCMSupported
};
}
//# sourceMappingURL=useWebSSO.js.map