Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PreSignedUrl of createImportJob cant upload file .csv #6679

Open
khanwilson opened this issue Aug 28, 2024 · 11 comments
Open

PreSignedUrl of createImportJob cant upload file .csv #6679

khanwilson opened this issue Aug 28, 2024 · 11 comments
Assignees
Labels
documentation This is a problem with documentation. p3 This is a minor priority issue queued This issues is on the AWS team's backlog

Comments

@khanwilson
Copy link

khanwilson commented Aug 28, 2024

Describe the issue

i have downloaded template.csv and include some row data in.
i want create job import users by aws sdk, by that step:

  • create CognitoIdentityServiceProvider
  • use provider.createUserImportJob(params) with params: JobName, UserPoolId, CloudWatchLogsRoleArn.
  • get PreSignedUrl from response createUserImportJob.
    call Put (by axios, postman) with header 'Content-Type': 'text/csv'. when time has valid but i always got 403
<Code>SignatureDoesNotMatch</Code>
   <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
Untitled
  • got that error so i cant run startImportJob.

With params of createUserImportJob, i have do manually on Amazon Cognito>User pools>my pool>Create import job. It run oke.
beside, i have check is my S3, i dont see any bucket name like https://aws-cognito-idp-user-import-lhr.s3.eu-west-2.amazonaws.com of first part in url PreSignedUrl. Why, createUserImportJob created link like that.
Untitled2

Please explain this problem, and help me solve it :(

Links

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#createUserImportJob-property

@khanwilson khanwilson added documentation This is a problem with documentation. needs-triage This issue or PR still needs to be triaged. labels Aug 28, 2024
@aBurmeseDev
Copy link
Member

Hi @khanwilson - thanks for reaching out.

  • create CognitoIdentityServiceProvider
  • use provider.createUserImportJob(params) with params: JobName, UserPoolId, CloudWatchLogsRoleArn.
  • get PreSignedUrl from response createUserImportJob.

When you call the createUserImportJob method, Amazon Cognito generates a pre-signed URL for you to upload the CSV file to an S3 bucket. This pre-signed URL includes a signature that is calculated based on your AWS credentials and other request parameters.

  • call Put (by axios, postman) with header 'Content-Type': 'text/csv'. when time has valid but i always got 403 SignatureDoesNotMatch
  • The request signature we calculated does not match the signature you provided. Check your key and signing method.

When you try to upload the CSV file using a tool like Postman or Axios, you need to ensure that the request is sent exactly as specified in the pre-signed URL, including the headers and the request body. Any deviation from the expected request format will result in a SignatureDoesNotMatch error as the signature calculated by AWS will not match the signature you provided.

Regarding the S3 bucket name in the pre-signed URL, Amazon Cognito uses an internal S3 bucket managed by the service for user import jobs. This bucket is not visible in your AWS account and you cannot access it directly. The pre-signed URL includes a bucket name like aws-cognito-idp-user-import-lhr.s3.eu-west-2.amazonaws.com which is a bucket used by the Cognito service.

Here are a few suggestions:

  • Check the pre-signed URL expiration: Pre-signed URLs have a limited validity period typically a few hours. If the URL has expired, you will receive a SignatureDoesNotMatch error.
  • Verify the request headers: Ensure that you're sending the Content-Type: text/csv header exactly as specified in the pre-signed URL. Any deviation in the header name or value will cause a signature mismatch.
  • Use the AWS SDK or AWS CLI: Instead of using a third-party tool like Postman or Axios, you can try uploading the CSV file using AWS SDK or AWS CLI. We handle the signature calculation automatically reducing the chances of errors.
  • Check the AWS credentials: Ensure that you're using the correct AWS credentials (access key and secret key) when creating the Cognito Identity Provider client. Incorrect or expired credentials can cause signature mismatches.

Hope it helps.
Best,
John

@aBurmeseDev aBurmeseDev self-assigned this Aug 28, 2024
@aBurmeseDev aBurmeseDev added response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. p2 This is a standard priority issue and removed needs-triage This issue or PR still needs to be triaged. labels Aug 28, 2024
@khanwilson
Copy link
Author

khanwilson commented Aug 29, 2024

Hi @khanwilson - thanks for reaching out.

  • create CognitoIdentityServiceProvider
  • use provider.createUserImportJob(params) with params: JobName, UserPoolId, CloudWatchLogsRoleArn.
  • get PreSignedUrl from response createUserImportJob.

When you call the createUserImportJob method, Amazon Cognito generates a pre-signed URL for you to upload the CSV file to an S3 bucket. This pre-signed URL includes a signature that is calculated based on your AWS credentials and other request parameters.

  • call Put (by axios, postman) with header 'Content-Type': 'text/csv'. when time has valid but i always got 403 SignatureDoesNotMatch
  • The request signature we calculated does not match the signature you provided. Check your key and signing method.

When you try to upload the CSV file using a tool like Postman or Axios, you need to ensure that the request is sent exactly as specified in the pre-signed URL, including the headers and the request body. Any deviation from the expected request format will result in a SignatureDoesNotMatch error as the signature calculated by AWS will not match the signature you provided.

Regarding the S3 bucket name in the pre-signed URL, Amazon Cognito uses an internal S3 bucket managed by the service for user import jobs. This bucket is not visible in your AWS account and you cannot access it directly. The pre-signed URL includes a bucket name like aws-cognito-idp-user-import-lhr.s3.eu-west-2.amazonaws.com which is a bucket used by the Cognito service.

Here are a few suggestions:

  • Check the pre-signed URL expiration: Pre-signed URLs have a limited validity period typically a few hours. If the URL has expired, you will receive a SignatureDoesNotMatch error.
  • Verify the request headers: Ensure that you're sending the Content-Type: text/csv header exactly as specified in the pre-signed URL. Any deviation in the header name or value will cause a signature mismatch.
  • Use the AWS SDK or AWS CLI: Instead of using a third-party tool like Postman or Axios, you can try uploading the CSV file using AWS SDK or AWS CLI. We handle the signature calculation automatically reducing the chances of errors.
  • Check the AWS credentials: Ensure that you're using the correct AWS credentials (access key and secret key) when creating the Cognito Identity Provider client. Incorrect or expired credentials can cause signature mismatches.

Hope it helps. Best, John

  • i have checked my case, my Pre-signed has not expired, header like img i was attached above it has Content-Type: text/csv.
    i tried with axios or https like
const csvContent = file.buffer;
const response = await axios.put(preSignedUrl, csvContent, {
        headers: {
          'Content-Type': 'text/csv',
        },
      });

but, i still got the same SignatureDoesNotMatch error.

  • i check AWS credentials, my project has use accessKeyId and secretAccessKey of IAM>Users account has that permissions below, im not sure that is enough for this case: createImportJob > uploadCsvToS3 > startImportJob.
image

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. label Aug 30, 2024
@aBurmeseDev
Copy link
Member

Can you share your code to help us understand the issue better?

@aBurmeseDev aBurmeseDev added response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. closing-soon This issue will automatically close in 4 days unless further comments are made. labels Sep 3, 2024
@bk-harish
Copy link

@aBurmeseDev
I am also getting this error and still unable to resolve it.
Did you find any solution to this problem?

@zshzbh
Copy link
Contributor

zshzbh commented Nov 18, 2024

Hey @bk-harish,

The AWS SDK for JavaScript v2 has entered maintenance mode on September 8, 2024 and will be reaching end-of-support on September 8, 2025. During maintenance mode, AWS will limit SDK releases to address critical bug fixes and security issues only. The SDK will not receive API updates for new or existing services, or be updated to support new regions.

We recommend that you migrate to AWS SDK for JavaScript v3.

The AWS SDK for JavaScript v3 is the latest and recommended version, which has been GA since December 2020. Here is why and how you should use AWS SDK for JavaScript v3. You can try our migration scripts in aws-sdk-js-codemod to migrate your application from v2 to v3.

To get help with your migration, please follow our general guidelines to open an issue and choose guidance. To give feedback on and report issues in the v3 repo, please refer to Giving feedback and contributing.

If you are facing this issue in js sdk v3, please open a ticket in https://github.com/aws/aws-sdk-js-v3.

@bk-harish
Copy link

Hi @zshzbh,
I migrated my code from v3 to v3 and still getting the same issue when trying to upload the file to the resigned URL received in the response of createUserImportJob method.

@zshzbh zshzbh transferred this issue from aws/aws-sdk-js Nov 19, 2024
@zshzbh zshzbh assigned zshzbh and unassigned aBurmeseDev Nov 19, 2024
@zshzbh
Copy link
Contributor

zshzbh commented Nov 19, 2024

I have transferred this issue to js sdk v3 repo.

@bk-harish Could you please send us the minimal code reproduction?

Thanks!
Maggie

@zshzbh zshzbh removed the closing-soon This issue will automatically close in 4 days unless further comments are made. label Nov 19, 2024
@zshzbh zshzbh reopened this Nov 19, 2024
@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. label Nov 20, 2024
@bk-harish
Copy link

bk-harish commented Nov 20, 2024

const { CognitoIdentityProviderClient,
    ListUsersCommand,
    AdminCreateUserCommand,
    AdminUpdateUserAttributesCommand,
    adminGetUserCommand,
    CreateUserImportJobCommand,
    startUserImportJobCommand,
    adminDisableUserCommand,
    adminDeleteUserCommand
} = require("@aws-sdk/client-cognito-identity-provider"),
    fetch = require('node-fetch');

const userPoolId = process.env.AWS_USER_POOL_ID,
    cloud_watch_arn = process.env.AWS_CLOUD_WATCH_ARN;

// Initialize CognitoIdentityServiceProvider.
const cognito = new CognitoIdentityProviderClient({
    UserPoolId: userPoolId,
    "region": process.env.AWS_COGNITO_REGION,
    credentials: {
        "accessKeyId": process.env.AWS_ACCESS_KEY,
        "secretAccessKey": process.env.AWS_SECRET_ACCESS_KEY
    }
});


// Get list of all Users
exports.getList = (req, res) => {
    try {
        let requestParams = req.body;
        let params = {
            UserPoolId: userPoolId,
            Limit: requestParams.limit_per_page ? requestParams.limit_per_page : 10
        };
        if (requestParams.next_page_token) {
            params.PaginationToken = requestParams.next_page_token;
        }
        cognito
        const command = new ListUsersCommand(params);
        return cognito.send(command).then(response => {
            return res.send(response);
        }).catch(exception => {
            console.log('exception get users', exception)
            return res.send({
                message:
                    exception.message || "Some error occurred while retrieving users."
            });
        });
    } catch (exception) {
        res.send(exception);
    }
};

//Add bulk user into cognito user pool
exports.addUserBulk = async (req, res) => {

    let userParams = req.body;
    let bulkUserFile = req.file ? req.file : false
    if (!bulkUserFile) {
        res.status(500).send({
            message: "For adding users in bulk, file is requried. "
        });
    }
    userParams;
    try {
        let payload = {
            UserPoolId: userPoolId,
            JobName: `${new Date().getTime()}_bulkUserUpload`,
            CloudWatchLogsRoleArn: cloud_watch_arn
        }
        let command = new CreateUserImportJobCommand(payload);
        return await cognito.send(command).then(async result => {

            let userImportJob = result.UserImportJob;
            if (userImportJob && userImportJob.PreSignedUrl) {

                let fileUploadResponse = await uploadFile(bulkUserFile, userImportJob.PreSignedUrl);
                if (fileUploadResponse.ok) {
                    console.log('File uploaded successfully!');
                    let jobParams = {
                        UserPoolId: userPoolId,
                        JobId: userImportJob.JobId
                    }
                    let startJobCommand = new startUserImportJobCommand(jobParams);
                    return await cognito.send(startJobCommand).then(result => {
                        return res.send(result);
                    }).catch(exception => {
                        console.log('exception start improt job', exception)
                        return res.send({
                            message:
                                exception.message || "Some error occurred while importing users."
                        });
                    });
                } else {
                    console.error('File upload failed:', fileUploadResponse.statusText);
                    return res.send(fileUploadResponse);
                }
            }
        }).catch(exception => {
            console.log('exception create import job', exception)
            return res.send({
                message:
                    exception.message || "Some error occurred while importing users."
            });
        });
    } catch (exception) {
        return res.send(exception);
    }
}

const uploadFile = async (file, presignedUrl) => {

    const response = await fetch(presignedUrl, {
        method: 'POST',
        body: file.buffer, // The file object
        headers: {
            'Content-Type': "text/csv"
    }).then(uploadResult => {
        return uploadResult.text();
    })
        .then(response => {
            console.log(response);
            return response;
        })
        .catch(exception => {
            console.log(exception);
            return exception;
        });

    return response;
};

Calling the function addUserBulk through API endpoint which is returning following error

<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>ASIA23GU7GYRRMZIPIQP</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256\n20241119T162817Z\n20241119/us-east-1/s3/aws4_request\neddb40d8146c41fcab3c8886cd51bb8cde0c855b3bc7e9840cd7c79bb21e87b1</StringToSign><SignatureProvided>f035f34ca28ff7466318760a33ac71bc4c868a0e39daa1ea7343d…72 74 2d 69 61 64 2e 73 33 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 78 2d 61 6d 7a 2d 73 65 72 76 65 72 2d 73 69 64 65 2d 65 6e 63 72 79 70 74 69 6f 6e 3a 0a 0a 68 6f 73 74 3b 78 2d 61 6d 7a 2d 73 65 72 76 65 72 2d 73 69 64 65 2d 65 6e 63 72 79 70 74 69 6f 6e 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes><RequestId>EG9MV2BDN979CBQA</RequestId><HostId>kVHbeEpt27fLsH1ilkJjE4KskYbUwORUWcAqQ6/DWY59NGIYCKIboBW3JocOoB3Hfl7JBMNCRnuz63E1O8DvG64wtmYiYaAR</HostId></Error>

@bk-harish
Copy link

@zshzbh
Any update on this issue?
Were you able to reproduce the issue using the code I shared?

@zshzbh
Copy link
Contributor

zshzbh commented Nov 27, 2024

Hey @bk-harish ,

I can reproduce this issue. I have a simplified reproduction and this is the code I have -

import { 
    CognitoIdentityProviderClient,
    CreateUserImportJobCommand,
    StartUserImportJobCommand
} from "@aws-sdk/client-cognito-identity-provider";

import fetch from 'node-fetch';
import fs from 'fs/promises';

const userPoolId = "us-east-1_XXXXXXX";
const cloud_watch_arn = "arn:aws:iam::XXXXXX:role/CognitoUserImportCloudWatchRole";

const cognito = new CognitoIdentityProviderClient({
    region: "us-east-1",
});

// Function to create CSV content in Cognito's required format
async function createUserImportCSV() {
    // CSV must follow Cognito's format with specific headers
    const csvContent = `cognito:username,email,given_name,family_name,phone_number,email_verified,phone_number_verified
[email protected],[email protected],Test,User1,+12345678901,TRUE,TRUE
[email protected],[email protected],Test,User2,+12345678902,TRUE,TRUE`;

    await fs.writeFile('users_import.csv', csvContent);
    console.log('Sample CSV file created: users_import.csv');
    return csvContent;
}

// Function to upload file using presigned URL
async function uploadFile(presignedUrl, fileContent) {
    try {
        const response = await fetch(presignedUrl, {
            method: 'PUT',
            body: fileContent,
            headers: {
                'Content-Type': 'text/csv',
                'x-amz-server-side-encryption': 'aws:kms'
            }
        });

        if (!response.ok) {
            const text = await response.text();
            throw new Error(`Upload failed: ${text}`);
        }

        console.log('File uploaded successfully');
        return response;
    } catch (error) {
        console.error('Error uploading file:', error);
        throw error;
    }
}

// Main function to handle user import
async function importUsers() {
    try {
        // Create the import job
        const timestamp = new Date().getTime();
        const jobName = `bulk_import_${timestamp}`;

        const createJobCommand = new CreateUserImportJobCommand({
            UserPoolId: userPoolId,
            JobName: jobName,
            CloudWatchLogsRoleArn: cloud_watch_arn
        });

        console.log('Creating import job...');
        const createJobResponse = await cognito.send(createJobCommand);
        const importJob = createJobResponse.UserImportJob;

        if (!importJob || !importJob.PreSignedUrl) {
            throw new Error('Failed to get presigned URL');
        }

        console.log('Import job created:', {
            JobId: importJob.JobId,
            JobName: importJob.JobName,
            Status: importJob.Status
        });

        // Create and upload the CSV file
        console.log('Creating CSV content...');
        const csvContent = await createUserImportCSV();

        // Upload the file using presigned URL
        console.log('Uploading file...');
        await uploadFile(importJob.PreSignedUrl, csvContent);

        // Start the import job
        console.log('Starting import job...');
        const startJobCommand = new StartUserImportJobCommand({
            UserPoolId: userPoolId,
            JobId: importJob.JobId
        });

        const startJobResponse = await cognito.send(startJobCommand);
        console.log('Import job started:', startJobResponse);

        return {
            jobId: importJob.JobId,
            status: startJobResponse.UserImportJob.Status
        };
    } catch (error) {
        console.error('Error in importUsers:', error);
        throw error;
    }
}



// Test the import
async function test() {
    try {
        console.log('Starting user import...');
        const result = await importUsers();
        console.log('Import initiated:', result);

        // Optional: Check status after a delay
        if (result.jobId) {
            console.log('Waiting 5 seconds to check status...');
            await new Promise(resolve => setTimeout(resolve, 5000));
            
        }
    } catch (error) {
        console.error('Test failed:', error);
    }
}

// Run the test
test().catch(console.error);

And I got error -

<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<AWSAccessKeyId>XXXXX</AWSAccessKeyId>
<StringToSign>AWS4-HMAC-SHA256 XXXXX 20241127/us-east-1/s3/aws4_request XXXXX</StringToSign>
<SignatureProvided>XXXXXX</SignatureProvided>
<StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 34 31 31 32 37 54 30 31 32 30 35 39 5a 0a 32 30 32 34 31 31 32 37 2f 75 73 2d 65 61 73 74 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 36 61 62 30 63 63 32 34 30 64 66 66 62 37 38 66 36 34 38 35 32 64 36 39 61 66 30 30 63 30 62 62 38 38 35 62 34 39 32 39 32 39 34 61 30 31 39 38 63 34 32 32 63 38 36 30 30 30 32 35 65 34 34 34</StringToSignBytes>
<CanonicalRequest>GET /XXXXXXXX/us-east-1_XmXXXXtUx/import-P67oXygSzF X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA23GU7GYR5BNWQGHL%2F20241127%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20241127T012059Z&X-Amz-Expires=899&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEJD%2F%2F%2F%2F%2F%2F%2F%2F%2F%XXXXX%2B9d4OiGyCW3YLTvwqsQUIORAFGgw3NDU2MjM0Njc1NTUiDMERJn9VppgPurIYvyqOBQiD2M%2BgBI2exD8irNtlDYSOtEvJbncJ5obt6fm8L0UOisD3NxcmVXY1t12VOqj7r04PUK1R%2B3hDOE7voXOU71RymsQYv1X1wvglHj1Ya3Hu995Cocglo2UCI6fihzIV2sKkZHHT178JMBcRD%2B8XMaVH9bdJWNM2Q7gpDwgEFnOwx0W7pLTJ1iJBYh8JgI%2BVxPkdKZvXFfKXOSAe9qIYNM5%2BYibYyEdjxvW%2BIh9VetjtoAE4vWLNJia9b9fE64IejNuwNhTtKPB4UIW2ckLjfnHnEW2uw54o45fr3nJeae3GQv0QJfvLNo%2BPsumhzjaFmIJIVxUH%2BUR6NUIqN5znn%2BFzv8unrO%2FPznhNoXG4FOlDuVlLBrHU%2FIkoJ4LJBqwY6%2FSH7B2JCh6VfTS46EgqTkOiXShaGMj8TfpipdPCtxYjnKrPxqwWGOPKfxDGt1Cn93B9FIunTkgmy2dslRb9GcHRv9B03S0VTWOgSqUdtb6EP3RU49C0wx3dseSXtPgePCCW6274cT%2FhutwHWkBH63j7DUf11pB4ixPUcjPujFvSuvJ0ZmtNQOjNJPrqMDZ9%2FKY8GP9f6Ix6qTVbhGoPXJE6mvBlOaBbacNv6jwI%2Bg11O1JG3uCvO3zi3cRgsQjTPpf%2BnGqnFGxRo2kTm3gEdWvIfg8AFHg2IsrJYcx1YzeFVP64FGOW672GBRE1uKIQv%2FzvYsCoq%2F8crj6TpC6p35yUb3dfZH%2FmlVQtgCNWxjxdQBopFColdBoprtJl18Q%2FVodFnEUJb93uukHgiaaaOK9vi%2FLIbHxezOBvVOVvZSnWQgHrQ1jTcFPYkxF98HbUtkJurv9xAdVXpwAoB76Qc5GT63suuh4EBq4z2dFMFTD3vJm6BjqxAavYRro5uxZ94jqkjIXSAPV820b0DPVpCHYTz4pFEYhZJ4GSfp0N8yoqjOJ6O7NAT6MYEwJwnFnX2lnZ9u5PY4wF89tWLbsTBlZ3iK9FQyUa8a7A3bq6o6DAZgAmCpcn%2Ba0M%2BUPOF%2BeAFfhy5%2B4gDD%2FhniumEMYYHJe40kFHVQZ5pZvViUwZjgtYRemoqr9ZTZqhTcZtr27RUYX9O4Jqtvh0iaY5RYUcx36z441%2BAEkomQ%3D%3D&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption host:aws-cognito-idp-user-import-iad.s3.amazonaws.com x-amz-server-side-encryption: host;x-amz-server-side-encryption UNSIGNED-PAYLOAD</CanonicalRequest>
<CanonicalRequestBytes>47 45 54 0a 2f 34 37 31 31 31 32 36 32 33 32 30 36 2f 75 73 2d 65 61 73 74 2d 31 5f 58 6d 58 68 51 55 74 55 78 2f 69 6d 70 6f 72 74 2d 50 36 37 6f 58 79 67 53 7a 46 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 53 49 41 32 33 47 55 37 47 59 52 35 42 4e 57 51 47 48 4c 25 32 46 32 30 32 34 31 31 32 37 25 32 46 75 73 2d 65 61 73 74 2d 31 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 32 34 31 31 32 37 54 30 31 32 30 35 39 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 38 39 39 26 58 2d 41 6d 7a 2d 53 65 63 75 72 69 74 79 2d 54 6f 6b 65 6e 3d 49 51 6f 4a 62 33 4a 70 5a 32 6c 75 58 32 56 6a 45 4a 44 25 32 46 25 32 46 25 32 46 25 32 46 25 32 46 25 32 46 25 32 46 25 32 46 25 32 46 25 32 46 77 45 61 43 58 56 7a 4c 57 56 68 63 33 51 74 4d 53 4a 48 4d 45 55 43 49 46 66 75 38 65 67 6a 6a 72 55 35 79 34 36 37 48 49 44 6a 48 6b 51 66 4c 38 66 7a 32 33 35 71 34 64 4b 55 72 6b 4c 70 63 53 4e 36 41 69 45 41 39 6d 38 69 65 6c 50 69 70 4c 30 75 47 6d 68 33 4a 56 46 32 64 59 52 35 6f 63 71 25 32 42 39 64 34 4f 69 47 79 43 57 33 59 4c 54 76 77 71 73 51 55 49 4f 52 41 46 47 67 77 33 4e 44 55 32 4d 6a 4d 30 4e 6a 63 31 4e 54 55 69 44 4d 45 52 4a 6e 39 56 70 70 67 50 75 72 49 59 76 79 71 4f 42 51 69 44 32 4d 25 32 42 67 42 49 32 65 78 44 38 69 72 4e 74 6c 44 59 53 4f 74 45 76 4a 62 6e 63 4a 35 6f 62 74 36 66 6d 38 4c 30 55 4f 69 73 44 33 4e 78 63 6d 56 58 59 31 74 31 32 56 4f 71 6a 37 72 30 34 50 55 4b 31 52 25 32 42 33 68 44 4f 45 37 76 6f 58 4f 55 37 31 52 79 6d 73 51 59 76 31 58 31 77 76 67 6c 48 6a 31 59 61 33 48 75 39 39 35 43 6f 63 67 6c 6f 32 55 43 49 36 66 69 68 7a 49 56 32 73 4b 6b 5a 48 48 54 31 37 38 4a 4d 42 63 52 44 25 32 42 38 58 4d 61 56 48 39 62 64 4a 57 4e 4d 32 51 37 67 70 44 77 67 45 46 6e 4f 77 78 30 57 37 70 4c 54 4a 31 69 4a 42 59 68 38 4a 67 49 25 32 42 56 78 50 6b 64 4b 5a 76 58 46 66 4b 58 4f 53 41 65 39 71 49 59 4e 4d 35 25 32 42 59 69 62 59 79 45 64 6a 78 76 57 25 32 42 49 68 39 56 65 74 6a 74 6f 41 45 34 76 57 4c 4e 4a 69 61 39 62 39 66 45 36 34 49 65 6a 4e 75 77 4e 68 54 74 4b 50 42 34 55 49 57 32 63 6b 4c 6a 66 6e 48 6e 45 57 32 75 77 35 34 6f 34 35 66 72 33 6e 4a 65 61 65 33 47 51 76 30 51 4a 66 76 4c 4e 6f 25 32 42 50 73 75 6d 68 7a 6a 61 46 6d 49 4a 49 56 78 55 48 25 32 42 55 52 36 4e 55 49 71 4e 35 7a 6e 6e 25 32 42 46 7a 76 38 75 6e 72 4f 25 32 46 50 7a 6e 68 4e 6f 58 47 34 46 4f 6c 44 75 56 6c 4c 42 72 48 55 25 32 46 49 6b 6f 4a 34 4c 4a 42 71 77 59 36 25 32 46 53 48 37 42 32 4a 43 68 36 56 66 54 53 34 36 45 67 71 54 6b 4f 69 58 53 68 61 47 4d 6a 38 54 66 70 69 70 64 50 43 74 78 59 6a 6e 4b 72 50 78 71 77 57 47 4f 50 4b 66 78 44 47 74 31 43 6e 39 33 42 39 46 49 75 6e 54 6b 67 6d 79 32 64 73 6c 52 62 39 47 63 48 52 76 39 42 30 33 53 30 56 54 57 4f 67 53 71 55 64 74 62 36 45 50 33 52 55 34 39 43 30 77 78 33 64 73 65 53 58 74 50 67 65 50 43 43 57 36 32 37 34 63 54 25 32 46 68 75 74 77 48 57 6b 42 48 36 33 6a 37 44 55 66 31 31 70 42 34 69 78 50 55 63 6a 50 75 6a 46 76 53 75 76 4a 30 5a 6d 74 4e 51 4f 6a 4e 4a 50 72 71 4d 44 5a 39 25 32 46 4b 59 38 47 50 39 66 36 49 78 36 71 54 56 62 68 47 6f 50 58 4a 45 36 6d 76 42 6c 4f 61 42 62 61 63 4e 76 36 6a 77 49 25 32 42 67 31 31 4f 31 4a 47 33 75 43 76 4f 33 7a 69 33 63 52 67 73 51 6a 54 50 70 66 25 32 42 6e 47 71 6e 46 47 78 52 6f 32 6b 54 6d 33 67 45 64 57 76 49 66 67 38 41 46 48 67 32 49 73 72 4a 59 63 78 31 59 7a 65 46 56 50 36 34 46 47 4f 57 36 37 32 47 42 52 45 31 75 4b 49 51 76 25 32 46 7a 76 59 73 43 6f 71 25 32 46 38 63 72 6a 36 54 70 43 36 70 33 35 79 55 62 33 64 66 5a 48 25 32 46 6d 6c 56 51 74 67 43 4e 57 78 6a 78 64 51 42 6f 70 46 43 6f 6c 64 42 6f 70 72 74 4a 6c 31 38 51 25 32 46 56 6f 64 46 6e 45 55 4a 62 39 33 75 75 6b 48 67 69 61 61 61 4f 4b 39 76 69 25 32 46 4c 49 62 48 78 65 7a 4f 42 76 56 4f 56 76 5a 53 6e 57 51 67 48 72 51 31 6a 54 63 46 50 59 6b 78 46 39 38 48 62 55 74 6b 4a 75 72 76 39 78 41 64 56 58 70 77 41 6f 42 37 36 51 63 35 47 54 36 33 73 75 75 68 34 45 42 71 34 7a 32 64 46 4d 46 54 44 33 76 4a 6d 36 42 6a 71 78 41 61 76 59 52 72 6f 35 75 78 5a 39 34 6a 71 6b 6a 49 58 53 41 50 56 38 32 30 62 30 44 50 56 70 43 48 59 54 7a 34 70 46 45 59 68 5a 4a 34 47 53 66 70 30 4e 38 79 6f 71 6a 4f 4a 36 4f 37 4e 41 54 36 4d 59 45 77 4a 77 6e 46 6e 58 32 6c 6e 5a 39 75 35 50 59 34 77 46 38 39 74 57 4c 62 73 54 42 6c 5a 33 69 4b 39 46 51 79 55 61 38 61 37 41 33 62 71 36 6f 36 44 41 5a 67 41 6d 43 70 63 6e 25 32 42 61 30 4d 25 32 42 55 50 4f 46 25 32 42 65 41 46 66 68 79 35 25 32 42 34 67 44 44 25 32 46 68 6e 69 75 6d 45 4d 59 59 48 4a 65 34 30 6b 46 48 56 51 5a 35 70 5a 76 56 69 55 77 5a 6a 67 74 59 52 65 6d 6f 71 72 39 5a 54 5a 71 68 54 63 5a 74 72 32 37 52 55 59 58 39 4f 34 4a 71 74 76 68 30 69 61 59 35 52 59 55 63 78 33 36 7a 34 34 31 25 32 42 41 45 6b 6f 6d 51 25 33 44 25 33 44 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 68 6f 73 74 25 33 42 78 2d 61 6d 7a 2d 73 65 72 76 65 72 2d 73 69 64 65 2d 65 6e 63 72 79 70 74 69 6f 6e 0a 68 6f 73 74 3a 61 77 73 2d 63 6f 67 6e 69 74 6f 2d 69 64 70 2d 75 73 65 72 2d 69 6d 70 6f 72 74 2d 69 61 64 2e 73 33 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 78 2d 61 6d 7a 2d 73 65 72 76 65 72 2d 73 69 64 65 2d 65 6e 63 72 79 70 74 69 6f 6e 3a 0a 0a 68 6f 73 74 3b 78 2d 61 6d 7a 2d 73 65 72 76 65 72 2d 73 69 64 65 2d 65 6e 63 72 79 70 74 69 6f 6e 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes>
<RequestId>X9FP7Z7E417A9KBN</RequestId>
<HostId>v5A88FXFV/eUOLHV/BbxbMZeVrneRcWD4K8ctvbryJuzgqdDpqLdSwmSjUBfG47DtxgzpRn7a/q0iSSL3upb/VGOinVDSUkI</HostId>
</Error>

I will bring this up with the team and will keep you updated.

Thanks!

@zshzbh zshzbh added investigating Issue is being investigated and/or work is in progress to resolve the issue. p3 This is a minor priority issue queued This issues is on the AWS team's backlog and removed investigating Issue is being investigated and/or work is in progress to resolve the issue. labels Nov 27, 2024
@zshzbh zshzbh removed the p2 This is a standard priority issue label Nov 27, 2024
@zshzbh
Copy link
Contributor

zshzbh commented Nov 27, 2024

aws-solutions project using axios to send the request -
https://github.com/aws-solutions/cognito-user-profiles-export-reference-architectu[…]4f43b735ae0963e531aebf47/source/workflow-import/import-users.js

I also tried to use axios but found no luck, this is my code -

import { 
    CognitoIdentityProviderClient,
    CreateUserImportJobCommand,
    StartUserImportJobCommand
} from "@aws-sdk/client-cognito-identity-provider";

import axios from 'axios';
import fs from 'fs/promises';

const userPoolId = "us-east-1_xxxxx";
const cloud_watch_arn = "arn:aws:iam::xxxxxxx:role/CognitoUserImportCloudWatchRole";

const cognito = new CognitoIdentityProviderClient({
    region: "us-east-1",
});

async function createUserImportCSV() {
    const csvContent = `cognito:username,email,given_name,family_name,phone_number,email_verified,phone_number_verified
[email protected],[email protected],Test,User1,+12345678901,TRUE,TRUE
[email protected],[email protected],Test,User2,+12345678902,TRUE,TRUE`;

    await fs.writeFile('users_import.csv', csvContent);
    console.log('Sample CSV file created: users_import.csv');
    return csvContent;
}

//  use axios 
async function uploadFile(presignedUrl, fileContent) {
    try {
        const options = {
            headers: {
                //'Content-Type': 'text/csv', // with or without content-type, both got Signature mismatch error
                'x-amz-server-side-encryption': 'aws:kms'
            },
            // Add these options to properly handle the response
            maxBodyLength: Infinity,
            maxContentLength: Infinity
        };
        const response = await axios.put(presignedUrl, fileContent, options);

        if (response.status !== 200) {
            throw new Error(`Upload failed: ${response.statusText}`);
        }

        console.log('File uploaded successfully');
        return response;
    } catch (error) {
        console.error('Error uploading file:', error);
        throw error;
    }
}

async function importUsers() {
    try {
        const timestamp = new Date().getTime();
        const jobName = `bulk_import_${timestamp}`;

        const createJobCommand = new CreateUserImportJobCommand({
            UserPoolId: userPoolId,
            JobName: jobName,
            CloudWatchLogsRoleArn: cloud_watch_arn
        });

        console.log('Creating import job...');
        const createJobResponse = await cognito.send(createJobCommand);
        const importJob = createJobResponse.UserImportJob;

        if (!importJob || !importJob.PreSignedUrl) {
            throw new Error('Failed to get presigned URL');
        }

        console.log('Import job created:', {
            JobId: importJob.JobId,
            JobName: importJob.JobName,
            Status: importJob.Status
        });

        console.log('Creating CSV content...');
        const csvContent = await createUserImportCSV();

        console.log('Uploading file...');
        await uploadFile(importJob.PreSignedUrl, csvContent);

        console.log('Starting import job...');
        const startJobCommand = new StartUserImportJobCommand({
            UserPoolId: userPoolId,
            JobId: importJob.JobId
        });

        const startJobResponse = await cognito.send(startJobCommand);
        console.log('Import job started:', startJobResponse);

        return {
            jobId: importJob.JobId,
            status: startJobResponse.UserImportJob.Status
        };
    } catch (error) {
        console.error('Error in importUsers:', error);
        throw error;
    }
}

async function test() {
    try {
        console.log('Starting user import...');
        const result = await importUsers();
        console.log('Import initiated:', result);

        if (result.jobId) {
            console.log('Waiting 5 seconds to check status...');
            await new Promise(resolve => setTimeout(resolve, 5000));
        }
    } catch (error) {
        console.error('Test failed:', error);
    }
}

test().catch(console.error);

If you want to try axios, feel free to try it.

I have brought this up with AWS JS SDK team and they will work on this issue.

Thanks!
Maggie

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation This is a problem with documentation. p3 This is a minor priority issue queued This issues is on the AWS team's backlog
Projects
None yet
Development

No branches or pull requests

4 participants