UNPKG

bento-auth-js

Version:

Authentication library for web applications of Bento-Platform

154 lines 7.7 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { useCallback, useEffect } from "react"; import { useDispatch } from "react-redux"; import { useNavigate, useLocation } from "react-router-dom"; import { DEFAULT_AUTH_SCOPE, useBentoAuthContext } from "./contexts"; import { useIsAuthenticated, useOpenIdConfig } from "./hooks"; import { PKCE_LS_STATE, PKCE_LS_VERIFIER, pkceChallengeFromVerifier, secureRandomString } from "./pkce"; import { tokenHandoff } from "./redux/authSlice"; import { buildUrlEncodedData, logMissingAuthContext, popLocalStorageItem } from "./utils"; export const LS_SIGN_IN_POPUP = "BENTO_DID_CREATE_SIGN_IN_POPUP"; export const LS_BENTO_WAS_SIGNED_IN = "BENTO_WAS_SIGNED_IN"; export const LS_BENTO_POST_AUTH_REDIRECT = "BENTO_POST_AUTH_REDIRECT"; const DEFAULT_REDIRECT = "/overview"; export const createAuthURL = (authorizationEndpoint_1, clientId_1, authCallbackUrl_1, ...args_1) => __awaiter(void 0, [authorizationEndpoint_1, clientId_1, authCallbackUrl_1, ...args_1], void 0, function* (authorizationEndpoint, clientId, authCallbackUrl, scope = "openid email") { const state = secureRandomString(); const verifier = secureRandomString(); localStorage.setItem(PKCE_LS_STATE, state); localStorage.setItem(PKCE_LS_VERIFIER, verifier); const { pathname, search, hash } = window.location; localStorage.setItem(LS_BENTO_POST_AUTH_REDIRECT, `${pathname}${search}${hash}`); return (`${authorizationEndpoint}?` + buildUrlEncodedData({ response_type: "code", client_id: clientId, state, scope, redirect_uri: authCallbackUrl, code_challenge: yield pkceChallengeFromVerifier(verifier), code_challenge_method: "S256", }).toString()); }); export const performAuth = (authorizationEndpoint_1, clientId_1, authCallbackUrl_1, ...args_1) => __awaiter(void 0, [authorizationEndpoint_1, clientId_1, authCallbackUrl_1, ...args_1], void 0, function* (authorizationEndpoint, clientId, authCallbackUrl, scope = "openid email") { window.location.href = yield createAuthURL(authorizationEndpoint, clientId, authCallbackUrl, scope); }); export const usePerformAuth = () => { const { authCallbackUrl, clientId, scope } = useBentoAuthContext(); const { data: openIdConfig } = useOpenIdConfig(); const authorizationEndpoint = openIdConfig === null || openIdConfig === void 0 ? void 0 : openIdConfig["authorization_endpoint"]; return useCallback(() => __awaiter(void 0, void 0, void 0, function* () { if (!authCallbackUrl || !clientId) { logMissingAuthContext("authCallbackUrl", "clientId"); throw new Error("Could not create auth URL; missing authCallbackUrl or clientId"); } if (!authorizationEndpoint) throw new Error("Could not create auth URL; missing authorization_endpoint"); window.location.href = yield createAuthURL(authorizationEndpoint, clientId, authCallbackUrl, scope !== null && scope !== void 0 ? scope : DEFAULT_AUTH_SCOPE); }), [authCallbackUrl, clientId, authorizationEndpoint, scope]); }; const useDefaultAuthCodeCallback = (onSuccessfulAuthentication) => { const dispatch = useDispatch(); const navigate = useNavigate(); const { authCallbackUrl, clientId } = useBentoAuthContext(); return useCallback((code, verifier) => __awaiter(void 0, void 0, void 0, function* () { if (!authCallbackUrl || !clientId) { logMissingAuthContext("authCallbackUrl", "clientId"); return; } const lastPath = popLocalStorageItem(LS_BENTO_POST_AUTH_REDIRECT); yield dispatch(tokenHandoff({ code, verifier, clientId, authCallbackUrl })); navigate(lastPath !== null && lastPath !== void 0 ? lastPath : DEFAULT_REDIRECT, { replace: true }); yield onSuccessfulAuthentication(); }), [dispatch, navigate, authCallbackUrl, clientId, onSuccessfulAuthentication]); }; export const setLSNotSignedIn = () => { localStorage.removeItem(LS_BENTO_WAS_SIGNED_IN); }; export const useHandleCallback = (callbackPath, onSuccessfulAuthentication, authCodeCallback = undefined, uiErrorCallback) => { const navigate = useNavigate(); const location = useLocation(); const { authCallbackUrl, clientId } = useBentoAuthContext(); const { data: oidcConfig } = useOpenIdConfig(); const isAuthenticated = useIsAuthenticated(); const defaultAuthCodeCallback = useDefaultAuthCodeCallback(onSuccessfulAuthentication); useEffect(() => { var _a; // Not used directly in this effect, but if we don't have it our auth callback / token handoff presumably won't // work properly, so we terminate early. if (!authCallbackUrl || !clientId) { logMissingAuthContext("authCallbackUrl", "clientId"); return; } // Ignore non-callback URLs if (!location.pathname.startsWith(callbackPath)) return; // End early if we don't have OpenID config (yet) if (!oidcConfig) return; // If we're already authenticated, don't try to reauthenticate if (isAuthenticated) { navigate(DEFAULT_REDIRECT, { replace: true }); return; } const params = new URLSearchParams(window.location.search); const error = params.get("error"); if (error) { uiErrorCallback(`Error encountered during sign-in: ${error}`); console.error(error); setLSNotSignedIn(); return; } const code = params.get("code"); if (!code) { // No code, don't do anything setLSNotSignedIn(); return; } const localState = popLocalStorageItem(PKCE_LS_STATE); if (!localState) { console.error("no local state"); setLSNotSignedIn(); return; } const paramState = params.get("state"); if (localState !== paramState) { console.error("state mismatch"); setLSNotSignedIn(); return; } const verifier = (_a = popLocalStorageItem(PKCE_LS_VERIFIER)) !== null && _a !== void 0 ? _a : ""; (authCodeCallback !== null && authCodeCallback !== void 0 ? authCodeCallback : defaultAuthCodeCallback)(code, verifier).catch((err) => { console.error(err); setLSNotSignedIn(); }); }, [ authCallbackUrl, authCodeCallback, callbackPath, clientId, defaultAuthCodeCallback, isAuthenticated, location, navigate, oidcConfig, uiErrorCallback, ]); }; export const checkIsInAuthPopup = (applicationUrl) => { try { const didCreateSignInPopup = localStorage.getItem(LS_SIGN_IN_POPUP); return window.opener && window.opener.origin === applicationUrl && didCreateSignInPopup === "true"; } catch (_a) { return false; } }; //# sourceMappingURL=performAuth.js.map