Search code examples
amazon-web-servicesamazon-cognitoaws-amplifyaws-sdk-jsaws-amplify-sdk-js

Getting credentials for logged in user via Amplify Auth


I am using AWS Amplify for a ReactJS application. The only two functional areas I am using from Amplify are Authentication and Hosting. These two are working fine, and a Cognito user pool associated with the project is working as expected, providing the logged in user to the React component after successful authentication.

My next step is to query other AWS resources outside of Amplify configuration, starting with an S3 bucket and a DynamoDB table. I am attempting to use AWS Client SDK for these, but am unable to figure out how to use the credentials of the currently logged in user.

I tried to use fromWebToken from @aws-sdk/credentials-providers but I do not have an Identity pool; I am using a Cognito user pool as only authenticated users have access to the web app. So I am stumped on how to proceed. My thought was that the current user credentials would automatically be used for any client request, but apparently it's not the case.

Here is the code I have; please note that this is only an attempt to show what I have tried, my question is quite simple: How do I get the currently authenticated user's credentials for use with S3 and other AWS Client SDK components?

    // user is the currently logged in user. I can see the accessToken etc. here.
    console.log(user.signInUserSession.accessToken);

    const client = new S3Client({
        region: "us-west-2", credentials: fromWebToken({

            clientConfig: {region: "us-west-2"},
            roleArn: "arn:aws:iam::...",  // Got these from IAM for authenticated users
            webIdentityToken: user.signInUserSession.accessToken.jwtToken
        })
    });

I try to use the client for downloading a file, but get the following error:

const command = new GetObjectCommand({
            Bucket: bucket,
            Key: key,
        });
const response = await client.send(command);

// Throws the error: No Cognito Identity pool provided for unauthenticated access

Any help is appreciated.


Solution

  • This turned out to be a three-step process:

    1. Define a new identity pool, and associate it with logged in users from the authenticated user pool from Amplify. The instructions are at https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-integrating-user-pools-with-identity-pools.html

    2. Set up CORS for the S3 bucket. This was not needed when using the SDK directly from a Lambda function, but for Amplify it was required. Instructions are at https://docs.aws.amazon.com/AmazonS3/latest/userguide/ManageCorsUsing.html

    3. Configure policy associated with the identity pool to give access to S3 bucket. This is usual IAM policy stuff.

    I used the following libraries/imports:

    import {S3Client, GetObjectCommand} from "@aws-sdk/client-s3";
    import {fromCognitoIdentityPool} from "@aws-sdk/credential-providers";
    import {Auth} from 'aws-amplify';
    
    const Identity_pool_id = <identity pool ID>;
    

    Finally, with the following code, I was able to get the file correctly:

        Auth.currentSession().then(data => {
            const client = new S3Client({
                    region: "us-west-2",
                    credentials: fromCognitoIdentityPool({
                        clientConfig: {region: "us-west-2"},
                        identityPoolId: Identity_pool_id,
                        logins: {
                            'cognito-idp.us-west-2.amazonaws.com/<user_pool_id>': data.getIdToken().getJwtToken()
                        }
                    })
                }
            );
            try {
                const command = new GetObjectCommand({
                    Bucket: bucket,
                    Key: key,
                    clientConfig: {region: "us-west-2"},
                });
                client.send(command).then(async (data) => {
                    // const stats = JSON.parse(data.Body.toString());
                    const data2 = await data.Body.transformToString();
                    console.log(data2);
                });
            } catch (err) {
                console.log(err);
            }
        });
    

    I was hoping to do this without Identity Pool so I will not mark this as final answer for next couple of days, in case there's another alternative.