InvalidParameterException: Invalid SourceUser: Cognito users with a username/password may not be passed in as a SourceUser, only as a DestinationUser
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
- [X] I have read the guide for submitting bug reports.
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
Vue
Amplify APIs
Authentication
Amplify Version
v6
Amplify Categories
auth
Backend
Amplify CLI
Environment information
# Put output below this line
System:
OS: macOS 14.4.1
CPU: (8) arm64 Apple M1
Memory: 143.50 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.11.1 - ~/.nvm/versions/node/v20.11.1/bin/node
Yarn: 1.22.19 - ~/.yarn/bin/yarn
npm: 7.20.0 - ~/.config/yarn/global/node_modules/.bin/npm
pnpm: 8.15.7 - ~/Library/pnpm/pnpm
Browsers:
Chrome: 124.0.6367.119
Safari: 17.4.1
npmPackages:
fast-xml-parser: ^4.3.2 => 4.3.2
mime-types: ^2.1.35 => 2.1.35
sharp: ^0.32.6 => 0.32.6
svg-parser: ^2.0.4 => 2.0.4
typescript: ^5.3.2 => 5.3.2
unzipper: ^0.10.14 => 0.10.14
npmGlobalPackages:
@angular/cli: 10.1.2
@aws-amplify/cli: 12.10.1
corepack: 0.23.0
graphql-schema-utilities: 1.1.8
npm: 10.2.4
Describe the bug
- Create an cognito account by amplify-js and not confirm this account
- Login with social (google) with amplify-js
- With preSignUp lambda, confirm user and set email_verified = true
- adminLinkProviderForUser return this error message (if user confirmed, adminLinkProviderForUser works fine)
InvalidParameterException: Invalid SourceUser: Cognito users with a username/password may not be passed in as a SourceUser, only as a DestinationUser
at Request.extractError (/var/task/cognito-pre-signup.js:82837:27)
at Request.callListeners (/var/task/cognito-pre-signup.js:86191:20)
at Request.emit (/var/task/cognito-pre-signup.js:86163:10)
at Request.emit (/var/task/cognito-pre-signup.js:84785:14)
at Request.transition (/var/task/cognito-pre-signup.js:84121:10)
at AcceptorStateMachine.runTo (/var/task/cognito-pre-signup.js:91267:12)
at /var/task/cognito-pre-signup.js:91279:10
at Request.<anonymous> (/var/task/cognito-pre-signup.js:84137:9)
at Request.<anonymous> (/var/task/cognito-pre-signup.js:84787:12)
at Request.callListeners (/var/task/cognito-pre-signup.js:86201:18) {
code: 'InvalidParameterException',
'[__type]': 'See error.__type for details.',
time: 2024-05-03T04:17:02.634Z,
requestId: '5451e01d-2b33-4742-99e1-22148499fe4a',
statusCode: 400,
retryable: false,
retryDelay: 65.69485045768356
}
Expected behavior
adminLinkProviderForUser works fine and not return error
Reproduction steps
1/ Create account with amplif-js and not confirm code
2/ with preSignUp lamda, confirm user and set email_verified = true before adminLinkProviderForUser
- if user confirmed, adminLinkProviderForUser will not return error
3/ Although adminLinkProviderForUser return error but this account seem link success
Code Snippet
// google social login
import { signInWithRedirect, signOut } from 'aws-amplify/auth';
await signInWithRedirect({
provider: 'Google',
});
// preSignUp lambda trigger
import AWS from 'aws-sdk';
export const handler = async (
event: PreSignUpTriggerEvent,
context: Context,
callback: Callback
) => {
const CognitoService = new AWS.CognitoIdentityServiceProvider();
const getUser = async (userPoolId, email) => {
// get user from cognito
const users = await CognitoService.getListUsers(userPoolId, email);
const userNotExternalProvider = users.filter((u) => u.UserStatus !== 'EXTERNAL_PROVIDER');
return userNotExternalProvider[0];
};
const confirmUser = async (userPoolId, username) => {
const params = {
UserPoolId: userPoolId,
Username: username,
};
await CognitoService.adminConfirmSignUp(params).promise();
await CognitoService.adminUpdateUserAttributes({
UserAttributes: [
{
Name: 'email_verified',
Value: 'true',
},
],
UserPoolId: userPoolId,
Username: username,
}).promise();
};
const linkProviderUser = async (Username, event) => {
let destinationProvider = 'Cognito';
let destinationSub = Username;
if (Username.includes('_')) {
const indexOf = Username.indexOf('_');
destinationProvider = Username.slice(0, indexOf);
destinationSub = Username.slice(indexOf + 1);
}
const params = {
DestinationUser: {
ProviderName: destinationProvider,
ProviderAttributeValue: destinationSub,
},
SourceUser: {
ProviderName: 'Google',
ProviderAttributeValue: event.userName.slice(event.userName.indexOf('_') + 1),
ProviderAttributeName: 'Cognito_Subject',
},
UserPoolId: event.userPoolId,
};
const result = await CognitoService.adminLinkProviderForUser(params).promise();
};
if (event.triggerSource === 'PreSignUp_ExternalProvider') {
const userExist = await getUser(event.userPoolId, event.request.userAttributes.email); // get user created before (this user not confirm)
if (userExist?.UserStatus === 'UNCONFIRMED') {
await confirmUser(event.userPoolId, userExist.Username);
}
await linkProviderUser(userExist.Username, event);
}
};
Log output
// Put your logs below this line
aws-exports.js
No response
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response
Seem this error occur because my lambda run time > 5 seconds. And it trigger twice
And in second trigger, adminLinkProviderForUser() cause error because in first time, it linked success
Hey, @natuan62 👋. While there are some lambdas that are not supported by the Social Sign In (noted here in docs), it looks like your sign-in is working and lambda is being triggered. I'm wondering if the issue is on the CDK API side for Cognito and will try to reproduce this/dig further. Just to make sure we can reproduce this properly and understand the use case, are you just trying to link your users together that have used multiple social providers?
@cwomack Yes, I'm trying link current account with multi social (google, facebook...)
@natuan62 Could you please provide the params you're seeing getting passed to await CognitoService.adminLinkProviderForUser(params).promise()? Feel free to redact sensitive values if needed.