I have recently started to work with the AWS SDK and how a user can authenticate with Cognito in an identity pool.
When querying the credentials I have the following question:
To what extent do the following approaches differ?
approach: getId() and getCredentialsForIdentity():
const cognitoidentity = new AWS.CognitoIdentity()
var params = {
IdentityPoolId: 'STRING_VALUE', /* required */
AccountId: 'STRING_VALUE',
Logins: {
'<IdentityProviderName>': 'STRING_VALUE',
/* '<IdentityProviderName>': ... */
}
};
cognitoidentity.getId(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
var params = {
IdentityId: 'STRING_VALUE', /* required */
CustomRoleArn: 'STRING_VALUE',
Logins: {
'<IdentityProviderName>': 'STRING_VALUE',
/* '<IdentityProviderName>': ... */
}
};
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // data AccesKeyId,Expiration, SecretKey, SessionToken
});
approach:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: identityPoolId,
Logins:{
'Provider': jwtToken
},
region: "eu-central-1"
});
AWS.config.credentials.get(function(){
// Credentials will be available when this function is called.
const{ accessKeyId} = AWS.config.credentials
const {secretAccessKey} = AWS.config.credentials
const {sessionToken} = AWS.config.credentials
})
the credentials of the two attempts are different, the SessionToken is the same. What is the difference between the SecretKey obtained in the first attempt and the SecretAccesKey obtained in the second attempt?
What are the differences between the two attempts?
The first attempt : enhanced simpliefied authflow with GetId and GetCredentialsForIdentity
https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html
second attempt:
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/loading-browser-credentials-cognito.html
I am grateful for any help :)
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityCredentials.html
According to this it is doing the same thing in the background.The difference in syntax for SecretKey and SecretAccesKey appears to be purely cosmetic. I have noticed the same in boto3. Regardless, you can pass either with accesskey and sessionid to authenticate other AWS services.
Related
I'm trying to get a Quicksight embed URL in a lambda function,
The lambda function receives a jwtToken from the frontend created on a react app using aws amplify, all the cognito setup works well (userpool and identity pool), the user receives the role "arn:aws:iam::xx:role/Cognito_qa1_Admin" when logging in,
The role has permissions to quicksight:registerUser and quicksight:getDashboardEmbedUrl
var cognitoIdentity = new AWS.CognitoIdentity();
var params = {
IdentityPoolId: "eu-west-2:xxx-291d-xx-b9a7-8b27c73c796c", // your identity pool id here
Logins: {
// your logins here
"cognito-idp.eu-west-2.amazonaws.com/eu-west-2_xxx": event.jwtToken,
},
};
// Get cognito identity from jwtToken
cognitoIdentity.getId(params, function (err, data) {
if (err) {
return callback(err);
}
var roleArn = "arn:aws:iam::xx:role/Cognito_qa1_Admin"; // your cognito authenticated role arn here
data.Logins = params.Logins;
// Get credentials for the identity (it also does the AssumeRoleWithWebIdentity)
cognitoIdentity.getCredentialsForIdentity(data, function (err, data) {
console.log(data);
if (err) {
return callback(err);
}
// update credentials with web identity ones
AWS.config.update({
region: "eu-west-2",
accessKeyId: data.Credentials.AccessKeyId,
secretAccessKey: data.Credentials.SecretKey,
sessionToken: data.Credentials.SessionToken,
expiration: data.Credentials.Expiration,
});
const quicksight = new AWS.QuickSight();
var getDashboardParams = {
AwsAccountId: "xx",
DashboardId: "a048efb6-3d3c-xx-8920-xxx",
IdentityType: "IAM",
ResetDisabled: false,
SessionLifetimeInMinutes: 100,
UndoRedoDisabled: false,
};
var registerUserParams = {
AwsAccountId: "xxx",
Email: event.userEmail,
IdentityType: "IAM",
Namespace: "default",
UserRole: "READER",
IamArn: roleArn,
SessionName: event.payloadSub,
};
// register user, this one works well
quicksight.registerUser(registerUserParams, function (err, data) {
if (err) {
if (err.code !== "ResourceExistsException") {
console.log("error registering user");
return callback(err);
}
console.log("user already exists");
}
console.log("User registration data", data);
// Get dashboard url, this is the one failing with QuickSightUserNotFoundException
quicksight.getDashboardEmbedUrl(getDashboardParams, function (
err,
data
) {
if (err) {
console.log("getDashboardEmbedUrl error", err);
return callback(err);
}
callback(null, data);
});
});
});
});
Everything goes smooth, the credentials for the web identity are retrieved and set to the config, the registerUser call registers the user (or returns user already exists error)
But the getDashboardEmbedUrl fails with QuickSightUserNotFoundException: Could not find user information in QuickSight
If I call sts.getCallerIdentity after setting the credentials I get this
{
ResponseMetadata: { RequestId: 'd5cb26f1-f2f5-4148-87e5-74d6c998fb91' },
UserId: 'AROAU63RLM5WIRTFDRETQ:CognitoIdentityCredentials',
Account: 'xxx',
Arn: 'arn:aws:sts::xxx:assumed-role/Cognito_qa1_Admin/CognitoIdentityCredentials'
}
Any idea? Thanks a lot in advance
When registering the user the IdentityType has to be IAM but for getDashboardEmbedUrl it has to be type QUICKSIGHT and you need to pass UserArn which you can find in the response from registerUser
Have got the IdentityPool created and userPool too.
Region, AccountId, IdentityPoolId and roleArn passed as params do hold the correct values.
A call to CognitoIdentityCredentials
AWS.config.region = region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
AccountId: accountId,
IdentityPoolId: identityPoolId,
RoleArn: roleArn,
});
returns (sensitive credentials obfuscated)
{
"expired": true,
"expireTime": null,
"refreshCallbacks": [],
"params": {
"AccountId": "9999999999",
"IdentityPoolId": "eu-west-2:bcfbd1c9-1234-1234-1234-423be5c3f7d8",
"RoleArn": "arn:aws:iam: : 999999999:role/Cognito_ElasticSearchIdentityPoolAuth_Role"
},
"data": null,
"_identityId": null,
"_clientConfig": {}
}
I would expect this call to return accessKeyId and sessionToken.
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityCredentials.html
Copied from the CognitoIdentityCredentials API documentation:
If a RoleArn is provided, then this provider gets credentials using the AWS.STS.assumeRoleWithWebIdentity() service operation, after first getting an Open ID token from AWS.CognitoIdentity.getOpenIdToken().
Consequently, I suggest that you try something along the lines, starting with CognitoIdentity.getId():
const getIdParams = {
IdentityPoolId: // ...
AccountId: // ...
Logins: {
'<IdentityProviderName>': 'STRING_VALUE',
/* '<IdentityProviderName>': ... */
}
};
const {IdentityId} = await cognitoidentity.getId(getIdParams).promise();
const openIdTokenParams = {
IdentityId,
Logins: {
'<IdentityProviderName>': 'STRING_VALUE',
/* '<IdentityProviderName>': ... */
}
};
const {Token} = await cognitoidentity.getOpenIdToken(openIdTokenParams).promise();
const assumeWebIdentityParams = {
DurationSeconds: // ...
ProviderId: // ...
RoleArn: // ...
RoleSessionName: // ...
WebIdentityToken: Token
}
const {Credentials} = await sts.assumeRoleWithWebIdentity(assumeWebIdentityParams).promise();
console.log(Credentials);
// prints AccessKeyId, Expiration, SecretAccessKey and SessionToken
how can I get all Users from aws cognito?
I found this: list Users
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#listUsers-property
var cognito = new AWSCognito.CognitoIdentityServiceProvider;
cognito.listUsers(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
But when I do this I got this error:
No reagon defined ...
also tried this:
AWS.config.region = 'eu-central-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'eu-central-1:',
Logins: {
'cognito-idp.eu-central-1.amazonaws.com/eu-central-1_': result.getIdToken().getJwtToken()
}
});
here I got result is not defined ...
how can I fetch all Users?
This is an working example:
let params = {
UserPoolId: '<<PoolID>>',
AttributesToGet: [
'email',
'family_name',
'given_name',
'custom:client',
'phone_number'
],
Limit: 0,
};
this.awsSDKAuth().listUsers(params, (err, data) => {
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(data.Users);
}
});
These are my first steps in AWS in general and Cognito specifically. So please bear with me as I'm a bit confused by all the concepts and documention is not very easy to follow.
So I set up 3 lambda functions, one that creates a user, one that confirms a user and a last one that is supposed to authenticate the user.
The first 2 work fine, my user is created an confirmed. Now I'm stuck with the 3rd one which is supposed to return a token to be used in APIG, where I've set up a simple endpoint with my cognito authorizer.
Every token I get back returns Unauthorized when tested in the APIG/Authorizers/Cognito Pool Authorizers section.
My 'sign in' code is the following:
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.apiVersions = {
cognitoidentityserviceprovider: '2016-04-18'
};
AWS.config.region = 'us-east-1'; // Region
/*AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
});*/
var identityId = null;
var params = {
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
IdentityId: identityId,
Logins: {
'login.auth.MYPROJECT': 'MY_USERNAME'
},
TokenDuration: 86400
};
var cognito = new AWS.CognitoIdentity({
region: AWS.config.region
});
cognito.getOpenIdTokenForDeveloperIdentity(params, function(err, data) {
if (err) {
return callback(err);
}
else {
/*AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: params.IdentityPoolId
});*/
AWS.config.credentials.get(function(){
// Credentials will be available when this function is called.
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
callback(null, {
identityId: data.IdentityId,
token: data.Token,
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
sessionToken: sessionToken
});
});
}
});
}
Both token and sessionToken return Unauthorized. Can someone tell me what is missing here?
Much appreciated.
EDIT 2016-11-15
The 'register' lambda code:
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
});
var poolData = {
UserPoolId : 'MY_USER_POOL_ID',
ClientId : 'MY_CLIENT_ID'
};
var userPool = new AWS.CognitoIdentityServiceProvider(poolData);
var email = "myemail+" + Math.floor(Math.random() * (100 - 1) + 1) + "#example.com";
var params = {
ClientId: 'MY_CLIENT_ID',
Password: '1234567890',
Username: 'testaccount' + Math.floor(Math.random() * (100 - 1) + 1),
UserAttributes: [
{
Name: 'email',
Value: email
}
]
};
userPool.signUp(params, function(err, result){
if (err) {
console.log(err)
return;
}
callback(null, {
"message": "Hello from Lambda",
"data": result
});
});
};
My 'activate' lambda code is the following:
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
});
var poolData = {
UserPoolId : 'MY_USER_POOL_ID',
ClientId : 'MY_CLIENT_ID'
};
var userPool = new AWS.CognitoIdentityServiceProvider(poolData);
var email = "email_address#example.com";
var params = {
ClientId: 'MY_CLIENT_ID',
Username: 'test_username',
ForceAliasCreation: false,
ConfirmationCode: '927000'
};
userPool.confirmSignUp(params, function(err, result){
if (err) {
console.log(err)
return;
}
callback(null, {
"message": "Hello from Lambda",
"data": result
});
});
};
In APIG, I created a Cognito User Pool Authorizer, selected my user pool, gave it a name, and set the identity token source to 'method.request.header.Authorization'.
In my APIG resource under the Method Request, I've set Authorization to my Cognito User Pool Authorizer. Additionally, API Key Required is set to true and I've a couple of keys I was testing with and that caused no issues.
I hope this covers everything.
I am trying to create a lambda function to create a user whenever there is an update in one of the tables of dynamo db.
I have created a dynamodb table with a trigger. I get "adminCreateUser not a function" error when i run the below code in lambda.
lambda function:
exports.handler = function(event, context) {
// TODO implement
cognitoidentityserviceprovider.adminCreateUser(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
context.done(null, 'Hello from Lambda');
};
It should be just the code below. Maybe make sure adminCreateUser is in your main AWS SDK, it was only introduced pretty recently.
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.apiVersions = {
cognitoidentityserviceprovider: '2016-04-18'
};
AWS.config.update({accessKeyId: 'akid', secretAccessKey: 'secret'});
var cognito = new AWS.CognitoIdentityServiceProvider({
region: 'us-east-1'
});
params = {};
cognito.adminCreateUser(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else
console.log(data); // successful response
});
context.done(null, 'Hello from Lambda');
};