Error with Using Cognito Identity Pool with React App, NestJs Backend and Quicksight Embedding

Hello brothers and sisters,

Could someone please give me some direction on how I should proceed next? I have been stuck here for some time now.

My Architecture: My internal web application uses React and runs on Amplify with Cognito authentication. The backend, built with NestJS, runs on Beanstalk. I want my users who are logged in on my website to be able to see embedded Quick Sight dashboards/visuals.

I have already set up a user pool and identity pool in Cognito. The identity pool has this role: “Cognito_WebAuth_Role” with the following setup:

Role Permission:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "quicksight:GetDashboardEmbedUrl",
                "quicksight:ListDashboards",
                "quicksight:ListUserGroups",
                "quicksight:ListUsers",
                "quicksight:RegisterUser"
            ],
            "Resource": "*"
        }
    ]
}

Role Trust Relationships:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "quicksight.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "cognito-identity.amazonaws.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "cognito-identity.amazonaws.com:aud": "ap-southeast-2:b8c646ee-4444-4bc6-858a-bcfb998161b4"
                },
                "ForAnyValue:StringLike": {
                    "cognito-identity.amazonaws.com:amr": "authenticated"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::730109622289:user/abc-admin",
                    "arn:aws:iam::730109622289:user/cody-abc",
                    "arn:aws:iam::730109622289:root"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

I have also assigned this “Cognito_WebAuth_Role” to Quick Sight.

My NestJS Setup

quicksight.module.ts

import { Module } from '@nestjs/common';
import { QuicksightController } from './quicksight.controller';
import { QuicksightService } from './quicksight.service';
import { STSClient } from '@aws-sdk/client-sts';

@Module({
  imports: [],
  controllers: [QuicksightController],
  providers: [
    {
      provide: STSClient,
      useFactory: () => {
        return new STSClient({ region: 'ap-southeast-2' }); 
      },
    },
    {
      provide: 'ROLE_ARN',
      useValue:
        'arn:aws:iam::730109622289:role/Cognito_WebAuth_Role', 
    },
    QuicksightService, 
  ],
})
export class Quick SightModule {}

quicksight.service.ts

import { Injectable, Inject } from '@nestjs/common';
import { STSClient, AssumeRoleCommand } from '@aws-sdk/client-sts';
import {
  Quick SightClient,
  GetSessionEmbedUrlCommand,
} from '@aws-sdk/client-quicksight';

@Injectable()
export class QuicksightService {
  constructor(
    @Inject(STSClient) private stsClient: STSClient,
    @Inject('ROLE_ARN') private roleArn: string,
  ) {}

  async getQuick SightClient(): Promise<Quick SightClient> {
    console.log('Assuming role with ARN:', this.roleArn);
    console.log('Using region:', 'ap-southeast-2');
    const assumeRoleCommand = new AssumeRoleCommand({
      RoleArn: this.roleArn,
      RoleSessionName: 'Quick SightEmbedSession',
    });
    const { Credentials } = await this.stsClient.send(assumeRoleCommand);
    console.log('Credentials received:', Credentials);
    return new Quick SightClient({
      region: 'ap-southeast-2',
      credentials: {
        accessKeyId: Credentials.AccessKeyId,
        secretAccessKey: Credentials.SecretAccessKey,
        sessionToken: Credentials.SessionToken,
      },
    });
  }

  async getEmbedUrl(userContext: any): Promise<string> {
    try {
      const quickSightClient = await this.getQuick SightClient();
      const command = new GetSessionEmbedUrlCommand({
        AwsAccountId: '730109622289',
        EntryPoint: 'analyses/e4fa5030-23fa-2222-ad54-f448a206beb9',
        SessionLifetimeInMinutes: 100,
        UserArn:
          'arn:aws:iam::730109622289:role/Cognito_WebAuth_Role', 
      });

      const { EmbedUrl } = await quickSightClient.send(command);
      return EmbedUrl;
    } catch (error) {
      console.error('Error getting Quick Sight Embed URL:', error);
      throw error;
    }
  }
}

ERROR
When i make a request, i got this error

Failed to get Quick Sight embed URL: ValidationException: 1 validation error detected: Value ‘arn:aws:iam::730109622289:role/Cognito_WebAuth_Role’ at ‘userArn’ failed to satisfy constraint: Specified resource is not reachable in this region (‘ap-southeast-2’). Please check the arn format and region information

Confirm that everything has been set up in the same region ap-southeast-2’

Any suggestions into how to proceed to debug would be really appreciated. Thank you so muchhhhh!

@cody ,
The UserARN value is wrong. This needs to be Quick Sight user who has access to the dashboard.

You can run a AWS SDK for JavaScript v3 and in the response you will find the ARN.

Kind regards,
Koushik

@Koushik_Muthanna

Hi Koushik,

Thank you. Confirm it is working now.
Would you please clarify the following for me as well.
In my setup, all logged-in users view AWS Quick Sight dashboards via a single user identity, utilizing the AssumeRole feature to embed these dashboards into the application. This single user identity is used to authenticate and generate Quick Sight sessions for any user on my platform.

Given the pay-per-session pricing model of Quick Sight, where it is $0.30 per session up to a maximum of $5 per user per month, how does this pricing apply when a single Quick Sight user identity is shared across multiple actual users of my application? Specifically, if I have 50 actual users all accessing Quick Sight through this single assumed Quick Sight user, does the $5 cap still apply, or will I incur additional charges based on the number of distinct sessions these 50 users generate through the single Quick Sight user identity?

I’m trying to understand the cost implications of this setup and whether each session initiated by any of the 50 users counts separately towards the billing, despite all using the same Quick Sight user identity.

@cody ,

Quick Sight has pricing changes and this is effective for new accounts . If you had a Quick Sight enterprise edition before April 30th 2024, then you have time until 1st May 2025 when the new pricing will come into effect ( https://www.youtube.com/watch?v=H4jpT6RNZog ) .

For consumption of dashboards by your readers, every user should be a registered in Quick Sight user.

Specifically, if I have 50 actual users all accessing Quick Sight through this single assumed Quick Sight user, does the $5 cap still apply, or will I incur additional charges based on the number of distinct sessions these 50 users generate through the single Quick Sight user identity?

You should register all those 50 users in Quick Sight. The pricing will be applied for every individual user (Business Intelligence Service – Amazon QuickSight Pricing – AWS).

Once registered you have 2 possibilities :
1/ Either go with individual user pricing or
2/ Capacity pricing

If you decide that you don’t want to manage users in Quick Sight, then you can embed as anonymous user ( Embedding QuickSight dashboards for anonymous (unregistered) users - Amazon QuickSight ) for which capacity pricing is required ( Business Intelligence Service – Amazon QuickSight Capacity Pricing – AWS )

Kind regards,
Koushik