UNPKG

@openpass/openpass-js-sdk

Version:
152 lines 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const config_1 = require("../config"); const constants_1 = require("./constants"); const pkce_1 = require("./utils/pkce"); const state_1 = require("./utils/state"); const url_1 = require("./url"); const codes_1 = require("./error/codes"); const errors_1 = require("./error/errors"); const sdkTelemetry_1 = require("./utils/sdkTelemetry"); /** * Class which handles the redirect authorization flow. * To realize this flow this class implements the Authorization Code Flow with Proof Key for Code Exchange (PKCE). * The redirect flow involves redirecting to an authorization service, and then handle the login response send via the redirect. */ class RedirectAuth { constructor(openPassOptions, signInStateRepository, openPassAuthClient) { this.openPassOptions = openPassOptions; this.openPassApiClient = openPassAuthClient; this.signInStateRepository = signInStateRepository; } /** * Initiate the login flow by redirecting to the authorization server * @param options the login options */ async signIn(options) { var _a, _b; if (!options.redirectUrl) { throw new errors_1.SdkError("Error redirectUrl is invalid. Please use a valid redirectUrl"); } try { const verifier = (0, pkce_1.generateCodeVerifier)(); const authSession = { clientState: options.clientState, clientId: this.openPassOptions.clientId, redirectUrl: options.redirectUrl, codeVerifier: verifier, codeChallenge: await (0, pkce_1.generateCodeChallenge)(verifier), codeChallengeMethod: constants_1.PARAM_CODE_CHALLENGE_METHOD_VALUE, state: (0, state_1.generateStateValue)(), loginHint: options.loginHint, disableLoginHintEditing: options.disableLoginHintEditing, originatingUri: (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.href, allowUnverifiedEmail: (_b = options.allowUnverifiedEmail) !== null && _b !== void 0 ? _b : false, }; this.signInStateRepository.add(authSession); const loginUri = (0, url_1.buildAuthorizeUrl)((0, config_1.getOpenPassApiBaseUrl)(this.openPassOptions.baseUrl), config_1.config.SSO_AUTHORIZE_PATH, authSession, options.source, options.customQueryParameters); window.location.href = loginUri; } catch (error) { console.error("Unable to start a sign-in session", error); (0, sdkTelemetry_1.sendSdkTelemetryErrorEvent)("RedirectAuth.signIn", error, this.openPassApiClient); throw error; } } /** * Determines if a redirect authorization session is in progress, and the current browser url meets the conditions to consider it as a valid redirection from the * authorization server for the current login session. */ isAuthenticationRedirect() { try { // Parse the current URL query parameters const currentPageAuthenticationParameters = (0, url_1.parseAuthRedirectUrlParams)(window.location.search); // First check if the current URL has state and code, or error parameters. if (!(0, url_1.urlHasStateAndCodeOrErrorParameters)(currentPageAuthenticationParameters)) { return false; } // Get the current auth session, this contains the redirect url to check against. const authSession = this.signInStateRepository.get(); // If there is no auth session at this point, then we are unable to complete the redirect flow. if (!authSession) { console.warn("No authentication session found when checking authentication redirect, ensure a call to signIn via redirect has been made first"); (0, sdkTelemetry_1.sendSdkTelemetryInfoEvent)("RedirectAuth.isAuthenticationRedirect", "No auth session found", this.openPassApiClient); return false; } // If there is not redirect url in the auth session, then we are unable to complete the redirect flow. if (!authSession.redirectUrl) { console.warn("No redirect url found in the auth session, ensure a call to signIn via redirect has been made first"); (0, sdkTelemetry_1.sendSdkTelemetryInfoEvent)("RedirectAuth.isAuthenticationRedirect", "Auth session found, but redirect url was not set", this.openPassApiClient); return false; } // Check if the current URL is a valid redirect URL for the current auth session, including checking the redirect url is the same as the current page url (just origin and path). const redirectUrlMatchesCurrentUrlValue = (0, url_1.redirectUrlMatchesCurrentUrl)(window.location.href, authSession.redirectUrl); (0, sdkTelemetry_1.sendSdkTelemetryInfoEvent)("RedirectAuth.isAuthenticationRedirect", `validAuthenticationRedirectUrl is ${redirectUrlMatchesCurrentUrlValue}`, this.openPassApiClient); return redirectUrlMatchesCurrentUrlValue; } catch (error) { console.error("Unable to check if the current URL is a valid redirect URL for the current auth session", error); (0, sdkTelemetry_1.sendSdkTelemetryErrorEvent)("RedirectAuth.isAuthenticationRedirect", error, this.openPassApiClient); throw error; } } /** * Handles a login redirect and attempts to complete the authorization flow. */ async handleAuthenticationRedirect() { try { // Parse the current URL query parameters const currentPageAuthenticationParameters = (0, url_1.parseAuthRedirectUrlParams)(window.location.search); // First check if the current URL has state and code, or error parameters. if (!(0, url_1.urlHasStateAndCodeOrErrorParameters)(currentPageAuthenticationParameters)) { throw new errors_1.AuthError(codes_1.ERROR_CODE_INVALID_REDIRECT, "The current URL does not contain expected state and code or error parameters, cannot handle redirect", ""); } // Get the current auth session which contains all the required security parameters to complete the sign-in. const authSession = this.signInStateRepository.get(); // If there is no auth session at this point, then we are unable to complete the redirect flow. if (!authSession) { console.error("No auth session found, cannot handle redirect. Ensure a call to signIn via redirect has been made first"); throw new errors_1.AuthError(codes_1.ERROR_CODE_INVALID_REDIRECT, "No auth session found, cannot handle redirect. Ensure a call to signIn via redirect has been made first", ""); } // If there is not redirect url in the auth session, then we are unable to complete the redirect flow. if (!authSession.redirectUrl) { console.error("No redirect url found in the auth session, ensure a call to signIn via redirect has been made first"); throw new errors_1.AuthError(codes_1.ERROR_CODE_INVALID_REDIRECT, "No redirect url found in the auth session, ensure a call to signIn via redirect has been made first", ""); } // Check if the current URL is a valid redirect URL for the current auth session, including checking the redirect url is the same as the current page url (just origin and path). if (!(0, url_1.redirectUrlMatchesCurrentUrl)(window.location.href, authSession.redirectUrl)) { console.error("The current URL does not match the expected redirect URL, cannot handle redirect"); throw new errors_1.AuthError(codes_1.ERROR_CODE_INVALID_REDIRECT, "The current URL does not match the expected redirect URL, cannot handle redirect", ""); } // Remove the auth session from the repository, we will no longer need it whether the rest of this method passes or fails. this.signInStateRepository.remove(); // If there is a error parameter on the URL, then we have a error response from the authorization server. if (currentPageAuthenticationParameters.error) { throw new errors_1.AuthError(currentPageAuthenticationParameters.error, currentPageAuthenticationParameters.errorDescription ? currentPageAuthenticationParameters.errorDescription : "", currentPageAuthenticationParameters.errorUri ? currentPageAuthenticationParameters.errorUri : "", authSession.clientState); } if (currentPageAuthenticationParameters.state !== authSession.state) { console.error("The state parameter in the redirect URL does not match the state in the auth session, cannot complete the redirect flow"); throw new errors_1.AuthError(codes_1.ERROR_CODE_INVALID_AUTH_SESSION, "The state parameter in the redirect URL does not match the state in the auth session", "", authSession.clientState); } const tokens = await this.openPassApiClient.exchangeAuthCodeForTokens(currentPageAuthenticationParameters.code, authSession); const { idToken, rawIdToken, accessToken, refreshToken, tokenType, expiresIn } = tokens; return { clientState: authSession.clientState, originatingUri: authSession.originatingUri, idToken: idToken, rawIdToken: rawIdToken, accessToken: accessToken, rawAccessToken: accessToken, refreshToken: refreshToken, tokenType: tokenType, expiresIn: expiresIn, }; } catch (error) { (0, sdkTelemetry_1.sendSdkTelemetryErrorEvent)("RedirectAuth.handleAuthenticationRedirect", error, this.openPassApiClient); throw error; } } } exports.default = RedirectAuth; //# sourceMappingURL=redirect.js.map