Skip to content

Instantly share code, notes, and snippets.

@evgalak
Last active March 13, 2024 12:38
Show Gist options
  • Save evgalak/d0d1adf099e2d7bff741c16a89bf30ba to your computer and use it in GitHub Desktop.
Save evgalak/d0d1adf099e2d7bff741c16a89bf30ba to your computer and use it in GitHub Desktop.
PHP code snippet to generate signed URL of the AWS QuickSight embed dashboard
<?php
// In addition to explanations from:
// https://stackoverflow.com/questions/53773313/how-to-get-generate-aws-quicksight-secure-dashboard-url/54052069#54052069
use Aws\Sts\StsClient;
use Aws\Credentials\Credentials;
use Aws\QuickSight\QuickSightClient;
use Aws\CognitoIdentity\CognitoIdentityClient;
use Aws\QuickSight\Exception\QuickSightException;
class StatisticsController
{
/*
* Generate signed URL of the AWS QuickSight embed dashboard
*
* @param $qsDashboardId
* @return $qsDashboardUrl
* @throws Throwable
*/
function getQsDashboardUrl($qsDashboardId)
{
// $user = Auth::user();
// Authorised user
$user = (object) ['username'=>'***', 'email=>'***']
// Step 0: Get idToken from request headers
// $authorizationHeader = request()->header('Authorization');
// $idToken = trim(str_replace('Bearer', '', $authorizationHeader));
// Here we should have a valid ID tocken (from the cognito user pool, or other provider)
$idToken='******************************************************';
// Step 1: Get identity based on idToken
$cognitoIdentityClient = new CognitoIdentityClient([
'version' => 'latest',
'region' => 'eu-central-1',
'IdentityPoolId' => config('aws-cognito-auth.identity_pool_id') // IDENTITY pool id: 'eu-central-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
]);
$identity = $cognitoIdentityClient->getId([
'IdentityPoolId'=> config('aws-cognito-auth.identity_pool_id') ,
'Logins' => [
config('aws-cognito-auth.user_pool_url') => $idToken,
// USER pool url/id 'cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXXXXXXX' => $idToken
// Or other providers like Fb, Google, AD, etc.
]
]);
// Step 2A.1: Get identity credentials
$openIdToken = $cognitoIdentityClient->GetOpenIdToken([
'IdentityId'=> $identity['IdentityId'],
'Logins' => [
config('aws-cognito-auth.user_pool_url') => $idToken,
]
]);
// Step 2A.2: Instantiate StsClient
$stsClient = new StsClient([
'region' => 'eu-central-1',
'version' => 'latest',
'credentials' => false,
]);
// Step 2A.3: Request temporary credentials of role what should have policy with
// quicksight:RegisterUser, quicksight:GetDashboardEmbedUrl actions allowed
$role = $stsClient->assumeRoleWithWebIdentity([
'RoleArn' => config('aws-quicksight.embed_dashboard_role_arn'),
'RoleSessionName' => $user->username,
'WebIdentityToken' => $openIdToken['Token'],
]);
// Step 2A.4: Prepare credentials object
$credentialsObject = new Credentials(
$role['Credentials']['AccessKeyId'],
$role['Credentials']['SecretAccessKey'],
$role['Credentials']['SessionToken'],
(int) $role['Credentials']['Expiration']->format('U')
);
// Alternative scenario. If Quicksight is on a same AWS acc,
// then you can request credentials directly, it will auto assume default identity pool role for authorised users
//
/*
// Step 2B : Get identity credentials
$credentials = $cognitoIdentityClient->getCredentialsForIdentity([
'IdentityId'=> $identity['IdentityId'],
'Logins' => [
config('aws-cognito-auth.user_pool_url') => $idToken,
]
]);
// Step 2B.1: Prepare credentials object
$credentialsObject = new Credentials(
$credentials['Credentials']['AccessKeyId'],
$credentials['Credentials']['SecretKey'],
$credentials['Credentials']['SessionToken'],
(int) $credentials['Credentials']['Expiration']->format('U')
);
*/
// Step 3: Instantiate QS client in us-east-1(QS users repository is there even if your datasets are somewhere else)
$qsClient = new QuickSightClient([
'region' => 'us-east-1',
'version' => 'latest',
'credentials' => $credentialsObject
]);
// Step 3: Load/Register QS user client
$qsRegisterUserParams = [
'AwsAccountId' => config('aws-quicksight.account_id'),
'Email' => $user->email,
'IdentityType' => 'IAM', //| QUICKSIGHT,
'Namespace' => 'default',
'UserRole' => 'READER', //ADMIN | AUTHOR | READER | RESTRICTED_AUTHOR | RESTRICTED_READER,
'IamArn' => config('aws-quicksight.embed_dashboard_role_arn'),
'SessionName' => $user->username,
];
$qsUser = null;
// Step 3.1: Try to Load QS user info
try{
$qsUser = $qsClient->describeUser([
'AwsAccountId' => config('aws-quicksight.account_id'),
'Namespace' => 'default',
'UserName'=> config('aws-quicksight.embed_dashboard_role_name').'/'.$user->username,
]);
}
catch (QuickSightException $e){
//If a user is just not found procced to registration, in all other cases - throw an exception
throw_if($e->getAwsErrorCode() !== 'ResourceNotFoundException', $e);
}
// Step 3.1: If user not found - try to register
if(!$qsUser){
$qsUser = $qsClient->registerUser($qsRegisterUserParams);
}
// Step 4.1: Re-Instantiate QS client to region with datasources
$qsClient = new QuickSightClient([
'region' => config('aws-quicksight.datasets_region'),
'version' => config('aws-quicksight.version'),
'credentials' => $credentialsObject
]);
// Step 4.2: Get dashboard URL
$result = $qsClient->getDashboardEmbedUrl([
'AwsAccountId' => config('aws-quicksight.account_id'),
'DashboardId' => $qsDashboardId,
'IdentityType' => 'IAM',
'ResetDisabled' => false,
'SessionLifetimeInMinutes' => config('aws-quicksight.session_duration'),
'UndoRedoDisabled' => false,
'IamArn' => $qsUser['User']['Arn']
]);
return $result['EmbedUrl'];
}
}
?>
@michaeljberry
Copy link

michaeljberry commented May 8, 2020

Thank you for getting back to me! I originally started with 2B because my AWS and Quicksight were on the same account, but I started from square one with the code again using 2A method. However, I kept getting this error using 2A's method:

The request signature we calculated does not match the signature you provided.

It turns out that I missed the subtle change in the credential Object between 2B and 2A. The secret key in 2B is SecretKey but in 2A it's SecretAccessKey. Copy-pasta... you got me again!

@evgalak
Copy link
Author

evgalak commented May 8, 2020

Great that you have found it! So, does it works now?

@michaeljberry
Copy link

Yes, using method 2A works. Thank you again for documenting this and making it public!

@karki117
Copy link

karki117 commented Aug 6, 2020

Thanks for sharing the php.
I am working on embedding the Quicksight dashboard on Wordpress site.
I have done the following steps:

  1. policy:Quicksightembed: registeruser, stsassume, getembeddedurl
  2. Role: quicksightRole <>>attached the above policy(quicksightembed)
  3. Cognito userpool and identity pool created (this is currently being used on the wordpress site)
  4. built the graph and publish dashboard to all
  5. uploaded your php to the wordpress (parameters changed).

It is not working the webpage is blank. Could you please provide step guide to implement this on wordpress on linux?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment