UNPKG

@aws-amplify/auth

Version:
146 lines (143 loc) 6.54 kB
import { Amplify } from '@aws-amplify/core'; import { assertTokenProviderConfig, assertOAuthConfig, urlSafeEncode, isBrowser, AuthAction } from '@aws-amplify/core/internals/utils'; import '../utils/oauth/enableOAuthListener.mjs'; import { cognitoHostedUIIdentityProviderMap } from '../types/models.mjs'; import { getAuthUserAgentValue } from '../../../utils/getAuthUserAgentValue.mjs'; import { openAuthSession } from '../../../utils/openAuthSession.mjs'; import { assertUserNotAuthenticated } from '../utils/signInHelpers.mjs'; import { generateCodeVerifier } from '../utils/oauth/generateCodeVerifier.mjs'; import { generateState } from '../utils/oauth/generateState.mjs'; import '../utils/refreshAuthTokens.mjs'; import '../tokenProvider/errorHelpers.mjs'; import { oAuthStore } from '../utils/oauth/oAuthStore.mjs'; import '../tokenProvider/tokenProvider.mjs'; import { getRedirectUrl } from '../utils/oauth/getRedirectUrl.mjs'; import { handleFailure } from '../utils/oauth/handleFailure.mjs'; import { completeOAuthFlow } from '../utils/oauth/completeOAuthFlow.mjs'; import '../../../types/Auth.mjs'; import { createOAuthError } from '../utils/oauth/createOAuthError.mjs'; import { listenForOAuthFlowCancellation } from '../utils/oauth/cancelOAuthFlow.mjs'; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 /** * Signs in a user with OAuth. Redirects the application to an Identity Provider. * * @param input - The SignInWithRedirectInput object, if empty it will redirect to Cognito HostedUI * * @throws AuthTokenConfigException - Thrown when the user pool config is invalid. * @throws OAuthNotConfigureException - Thrown when the oauth config is invalid. */ async function signInWithRedirect(input) { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); assertOAuthConfig(authConfig); oAuthStore.setAuthConfig(authConfig); if (!input?.options?.prompt) { await assertUserNotAuthenticated(); } let provider = 'COGNITO'; // Default let idpIdentifier; if (typeof input?.provider === 'string') { provider = cognitoHostedUIIdentityProviderMap[input.provider]; } else if (input?.provider?.custom) { provider = input.provider.custom; } else if (input?.provider?.idpIdentifier) { ({ idpIdentifier } = input.provider); } return oauthSignIn({ oauthConfig: authConfig.loginWith.oauth, clientId: authConfig.userPoolClientId, provider, idpIdentifier, customState: input?.customState, preferPrivateSession: input?.options?.preferPrivateSession, options: { loginHint: input?.options?.loginHint, lang: input?.options?.lang, nonce: input?.options?.nonce, prompt: input?.options?.prompt, }, authSessionOpener: input?.options?.authSessionOpener, }); } const oauthSignIn = async ({ oauthConfig, provider, idpIdentifier, clientId, customState, preferPrivateSession, options, authSessionOpener, }) => { const { domain, redirectSignIn, responseType, scopes } = oauthConfig; const { loginHint, lang, nonce, prompt } = options ?? {}; const randomState = generateState(); const openAuthSession$1 = authSessionOpener || openAuthSession; /* encodeURIComponent is not URL safe, use urlSafeEncode instead. Cognito single-encodes/decodes url on first sign in and double-encodes/decodes url when user already signed in. Using encodeURIComponent, Base32, Base64 add characters % or = which on further encoding becomes unsafe. '=' create issue for parsing query params. Refer: https://github.com/aws-amplify/amplify-js/issues/5218 */ const state = customState ? `${randomState}-${urlSafeEncode(customState)}` : randomState; const { value, method, toCodeChallenge } = generateCodeVerifier(128); const redirectUri = getRedirectUrl(oauthConfig.redirectSignIn); if (isBrowser()) oAuthStore.storeOAuthInFlight(true); oAuthStore.storeOAuthState(state); oAuthStore.storePKCE(value); const params = new URLSearchParams([ ['redirect_uri', redirectUri], ['response_type', responseType], ['client_id', clientId], ]); // Add either identity_provider or idp_identifier, but not both if (idpIdentifier) { params.append('idp_identifier', idpIdentifier); } else { params.append('identity_provider', provider); } params.append('scope', scopes.join(' ')); loginHint && params.append('login_hint', loginHint); lang && params.append('lang', lang); nonce && params.append('nonce', nonce); prompt && params.append('prompt', prompt.toLowerCase()); params.append('state', state); if (responseType === 'code') { params.append('code_challenge', toCodeChallenge()); params.append('code_challenge_method', method); } // Using URL object is not supported in React Native as the `search` property is read-only // See: https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Blob/URL.js const oAuthUrl = `https://${domain}/oauth2/authorize?${params.toString()}`; // this will only take effect in the following scenarios: // 1. the user cancels the OAuth flow on web via back button, and // 2. when bfcache is enabled listenForOAuthFlowCancellation(oAuthStore); // the following is effective only in react-native as openAuthSession resolves only in react-native const { type, error, url } = (await openAuthSession$1(oAuthUrl, redirectSignIn, preferPrivateSession)) ?? {}; try { if (type === 'error') { throw createOAuthError(String(error)); } if (type === 'canceled') { throw createOAuthError(String(type)); } if (type === 'success' && url) { await completeOAuthFlow({ currentUrl: url, clientId, domain, redirectUri, responseType, userAgentValue: getAuthUserAgentValue(AuthAction.SignInWithRedirect), preferPrivateSession, }); } } catch (err) { await handleFailure(err); // rethrow the error so it can be caught by `await signInWithRedirect()` in react-native throw err; } }; export { signInWithRedirect }; //# sourceMappingURL=signInWithRedirect.mjs.map