@aws-amplify/auth
Version:
Auth category of aws-amplify
137 lines (135 loc) • 6.15 kB
JavaScript
;
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.signInWithRedirect = signInWithRedirect;
const core_1 = require("@aws-amplify/core");
const utils_1 = require("@aws-amplify/core/internals/utils");
require("../utils/oauth/enableOAuthListener");
const models_1 = require("../types/models");
const utils_2 = require("../../../utils");
const signInHelpers_1 = require("../utils/signInHelpers");
const oauth_1 = require("../utils/oauth");
const createOAuthError_1 = require("../utils/oauth/createOAuthError");
const cancelOAuthFlow_1 = require("../utils/oauth/cancelOAuthFlow");
/**
* 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 = core_1.Amplify.getConfig().Auth?.Cognito;
(0, utils_1.assertTokenProviderConfig)(authConfig);
(0, utils_1.assertOAuthConfig)(authConfig);
oauth_1.oAuthStore.setAuthConfig(authConfig);
if (!input?.options?.prompt) {
await (0, signInHelpers_1.assertUserNotAuthenticated)();
}
let provider = 'COGNITO'; // Default
let idpIdentifier;
if (typeof input?.provider === 'string') {
provider = models_1.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 = (0, oauth_1.generateState)();
const openAuthSession = authSessionOpener || utils_2.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}-${(0, utils_1.urlSafeEncode)(customState)}`
: randomState;
const { value, method, toCodeChallenge } = (0, oauth_1.generateCodeVerifier)(128);
const redirectUri = (0, oauth_1.getRedirectUrl)(oauthConfig.redirectSignIn);
if ((0, utils_1.isBrowser)())
oauth_1.oAuthStore.storeOAuthInFlight(true);
oauth_1.oAuthStore.storeOAuthState(state);
oauth_1.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
(0, cancelOAuthFlow_1.listenForOAuthFlowCancellation)(oauth_1.oAuthStore);
// the following is effective only in react-native as openAuthSession resolves only in react-native
const { type, error, url } = (await openAuthSession(oAuthUrl, redirectSignIn, preferPrivateSession)) ??
{};
try {
if (type === 'error') {
throw (0, createOAuthError_1.createOAuthError)(String(error));
}
if (type === 'canceled') {
throw (0, createOAuthError_1.createOAuthError)(String(type));
}
if (type === 'success' && url) {
await (0, oauth_1.completeOAuthFlow)({
currentUrl: url,
clientId,
domain,
redirectUri,
responseType,
userAgentValue: (0, utils_2.getAuthUserAgentValue)(utils_1.AuthAction.SignInWithRedirect),
preferPrivateSession,
});
}
}
catch (err) {
await (0, oauth_1.handleFailure)(err);
// rethrow the error so it can be caught by `await signInWithRedirect()` in react-native
throw err;
}
};
//# sourceMappingURL=signInWithRedirect.js.map