I'm looking to get temporary AWS credentials through the Cognito Identity pool. And then that credentials should access the AWS Transcribe service.
I've created an Identity pool and checked the option of unauthenticated user, so that I don't have to provide a token when I'm calling CognitoIdentityCredentials.
Then I attached the permission for transcribe service in the unauthenticated role(Cognito_TestIdentityPoolUnauth_Role-New).
But when I'm calling the CognitoIdentityCredentials, I'm not getting the credentials.
This is my code:-
const AWS = require('aws-sdk');
AWS.config.region = 'us-east-1';
// Configure the credentials provider to use your identity pool
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
identityPoolId: 'your_pool_id',
});
let accessKeyId, secretAccessKey, sessionToken;
// Make the call to obtain credentials
AWS.config.credentials.get(function(){
// Credentials will be available when this function is called.
accessKeyId = AWS.config.credentials.accessKeyId;
secretAccessKey = AWS.config.credentials.secretAccessKey;
sessionToken = AWS.config.credentials.sessionToken;
console.log('data', accessKeyId, secretAccessKey, sessionToken);
});
The acessKeyId, secretAccessKey and sessionToken is undefined. What am I missing here?
So to answer my own question. The latest credentials were somehow not being updated in the SDK. I'm also using the S3 service in the same function and the creds for that service are different. Here's the updated code which worked for me. And here's the thread that helped me.
const creds = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'identity_pool_id',
})
AWS.config.update({
region: 'us-east-1',
credentials: creds,
});
AWS.config.credentials.get(function () {
// Credentials will be available when this function is called.
const accessKeyId = AWS.config.credentials.accessKeyId;
const secretAccessKey = AWS.config.credentials.secretAccessKey;
const sessionToken = AWS.config.credentials.sessionToken;
console.log(accessKeyId, secretAccessKey, sessionToken);
});
PS:- Using node v14.
Related
I have a cognito userpool and i can successfully log into my app with the following code:
const authData = {
ClientId : '2222222222222', // Your client id here
AppWebDomain : '1111111111.auth.us-east-1.amazoncognito.com',
TokenScopesArray : ['openid'],
RedirectUriSignIn : 'https://app.domain.com',
RedirectUriSignOut : 'https://app.domain.com'
};
const CognitoAuth = AmazonCognitoIdentity.CognitoAuth;
const auth = new CognitoAuth(authData);
auth.userhandler = {
/**onSuccess: <TODO: your onSuccess callback here>,
onFailure: <TODO: your onFailure callback here>*/
onSuccess: function(result: any) {
console.log("COGNITO SUCCESS!");
console.log(result);
},
onFailure: function(err: any) {
console.log("COGNITO FAIL!");
console.log(err);
}
};
auth.getSession();
const curUrl = window.location.href;
auth.parseCognitoWebResponse(curUrl);
I now have an auth object that I would like to parlay into some sort of credentials for the aws-sdk that i have so that i can list items into an S3 bucket, assuming the correct policies in my attached roles.
something like this, but realize this doesn't work:
AWS.config.credentials = auth.toCredentials(); //<== hoping for magic
const s3 = new AWS.S3();
s3.listObjectsV2(listObjectsV2Params, function(err: any, data: any) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data.Contents[0]); // successful response
});
Is this possible, and if so how do i do that?
UDPATE
Accepted answer worked and was a big help, adding some additions for clarity along the lines of trouble I ran into.
const creds = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:b111111-1111-1111-1111-1111111', // <-- This is in your Federated Identity if you have that set up, you have to "edit" the identity pool to get it, logging into cognito its a different screen.
Logins: {
"cognito-idp.us-east-1.amazonaws.com/us-east-1_BBBB1BBBBV2B": result.idToken.jwtToken // <- this login [POOL ID] is not the pool ARN, you need it in this format.
}
});
this link helped me.
This is possible and following are the steps.
To allow AWS resources access for AWS Userpool Users, it also requires to configure AWS Identity Pools registering the UserPool as a provider.
The IAM Role assigned for the authenticated user needs to have access to S3.
Using the AWS SDK for Identity Pools, UserPools JWT token can be exchanged for temporal AccessKey and SecretKey to use AWS SDK for S3.
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IDENTITY_POOL_ID,
Logins: {
[USER_POOL_TOKEN]: result.idToken.jwtToken
}
});
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
} else {
console.log('Successfully logged!');
}
});
Inside the AWS.config.credentials.refresh callback you can call S3 since, the method internally will handle getting temporal credentials.
I'm developing a web application which uses AWS services backend size.
In this moment I use AWS Cognito to manage user sessions.
I'm developing the application with Angular 4 (using TypeScript / JavaScript language) and I found this useful class (In the JavaScript SDK for AWS Cognito) that should provide me with so many data that I need to display on the frontend:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html
The problem is that any method I invoke on this object, the console return this error:
Error: Missing region in config
at Request.VALIDATE_REGION (event_listeners.js:91)
at Request.callListeners (sequential_executor.js:105)
at callNextListener (sequential_executor.js:95)
at event_listeners.js:85
at finish (config.js:315)
at Config.getCredentials (config.js:360)
at Request.VALIDATE_CREDENTIALS (event_listeners.js:80)
at Request.callListeners (sequential_executor.js:101)
at Request.emit (sequential_executor.js:77)
at Request.emit (request.js:683)
I do not understand why this happens, because I have correctly configured the region, like this:
//Setting AWS credentials
AWS.config.region = environment.region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId : environment.identityPoolId
});
and if i use the instruction console.log(AWS.config.region), the console prints the correct region.
Why it continues to visualize that error?
The complete code:
var params = {
UserPoolId: environment.clientId,
};
//Setting AWS credentials
AWS.config.region = environment.region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId : environment.identityPoolId
});
this.cognitoidentityserviceprovider.listUsers(params, function(err, data) {
console.log(AWS.config.region)
if (err) console.log(err); // an error occurred
else console.log(data); // successful response
});
the path is always console.log(err) and the error is always Missing region in config. Why does this continue to happen?
How about if you do:
var CognitoIdentityServiceProvider = AWS.CognitoIdentityServiceProvider;
var client = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region: 'us-east-1' });
and you call listUsers on the client object? I believe region should be passed along when you initialize the service client.
This question is from a while ago, but this worked for me:
When you load the AWS SDK in order to create the AWS instance, you probably have to set the region there, like this:
const AWS = require('aws-sdk');
AWS.config.update({
region: 'us-west-1',
});
function(){
var identityService = new AWS.CognitoIdentityServiceProvider({
apiVersion: '2016-04-18'
});
...
}
Note that you might also have to set your credentials, depending on the action. In this case, you can use code like this:
const AWS = require('aws-sdk');
AWS.config.update({
region: 'us-west-1',
accessKeyId: process.env.YOUR_ACCESSKEY,
secretAccessKey: process.env.YOUR_SECRETKEY
});
function(){
var identityService = new AWS.CognitoIdentityServiceProvider({
apiVersion: '2016-04-18'
});
...
}
Im building a service + client using the following Amazon technologies:
Lambda
S3
API Gateway
Cognito
Federated Identities
Im using the serverless framework to build and deploy the API.
The client is a angular 1 app hosted in a S3 bucket.
The API endpoint is secured using AWS_IAM, the issue is that the first call to the API from my JS client is unauthorized, every call after that (using the same credentials) are authorized. I can see in my log that
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
is undefined the first time I make the call.
What I hope to achieve is that to retrieve the needed credentials so the first call succeeds.
The code below is what is used to get the credentials from Amazon Cognito and call the API. Im using the generated javascript SDK from AWS API Gateway to sign the request and call the API.
var authenticationDetails = new AWSCognito
.CognitoIdentityServiceProvider
.AuthenticationDetails(authenticationData);
var deferred = $q.defer();
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var logins = {}
logins["cognito url" + "/" + "cognito pool id"] = result.idToken.jwtToken
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: "identity pool id",
Logins: logins
});
AWS
.config
.credentials
.get(function () {
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
var config = {
accessKey: accessKeyId,
secretKey: secretAccessKey,
sessionToken: sessionToken
}
var apigClient = apigClientFactory.newClient(config);
apigClient
.endpointName(params, body, additionalParams)
.then(function (result) {
deferred.resolve(true)
})
.catch(function (result) {
deferred.resolve(false)
});
});
},
onFailure: function (err) {
alert(err);
}
});
return deferred.promise;
}
}
The problem was that I did not refresh the credentials after retrieval. For further reference the code used is below:
AWS.config.credentials.get(function() {
AWS.config.credentials.refresh(function(error) {
if (error) {
console.log(error);
// rejects promise with error message
} else {
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
console.log(accessKeyId);
console.log(secretAccessKey);
console.log(sessionToken);
}
});
});
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:2ce7b2c2-898f-4a26-9066-d4feff8ebfe4'
});
// Make the call to obtain credentials
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;
//var identityId = AWS.config.credentials.identityId;
return res.send({
accessKeyId: accessKeyId
});
});
All of the variables have null value. Why? What am i doing wrong? Is there another way to access it?
Also i am supposed to send a secretkey and token to retrieve a session key
UPDATE:
When i try this method, I get an error saying:
Error: NotAuthorizedException: Unauthenticated access is not supported for this identity pool.
AWS.config.credentials.get(function(err) {
if (err) {
console.log("Error: "+err);
return;
}
console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);
// Other service clients will automatically use the Cognito Credentials provider
// configured in the JavaScript SDK.
var cognitoSyncClient = new AWS.CognitoSync();
cognitoSyncClient.listDatasets({
IdentityId: AWS.config.credentials.identityId,
IdentityPoolId: ""
}, function(err, data) {
if ( !err ) {
console.log(JSON.stringify(data));
}
return res.send({
data: data
});
});
});
The exception you are seeing means that you have not set up your identity pool to allow unauthenticated identities.
You are not passing any logins in the logins map when you call get credentials, which means your user is un authenticated (which is not allowed by your identity pool).
Here is some documentation describing how to authenticate using external identity providers:
http://docs.aws.amazon.com/cognito/latest/developerguide/external-identity-providers.html
I posted here on the AWS forum
I'm using the aws-js-sdk v2.2.3 with the following code. I get data back with Credentials populated. When I try to use the credentials I get the error that they are invalid. I'm using the developer authenticated identities flow. I have both roles Auth & UnAuth. My identity pool looks like it's correct. The trust relationships look like they are pointing to the correct identity pool id. There are policies attached to the Auth role for S3 & DynamoDB. I'm at a loss. Any help would be appreciated.
javascript client side:
var cognitoidentity = new AWS.CognitoIdentity({region: 'us-east-1'});
var params = {
IdentityId: user.cognito_id,
Logins: {
'cognito-identity.amazonaws.com': user.cognito_token
}
};
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data.Credentials);
});
I console.log the Id & SecretKey and they are filled in.
var aws_creds = StateService.get('user').aws_creds;
console.log(aws_creds.AccessKeyId);
console.log(aws_creds.SecretKey);
AWS.config.update({ accessKeyId: aws_creds.AccessKeyId,
secretAccessKey: aws_creds.SecretKey,
endpoint: ENV.aws_dyndb_endpoint,
region: 'us-east-1'
});
var dynamodb = new AWS.DynamoDB();
console.log("user obj: ", StateService.get('user'));
var params = {
TableName: games_table_name,
KeyConditionExpression: "Id = :v1",
ExpressionAttributeValues: {
":v1": {"N": id}
}
};
return dynamodb.query(params);
My Solution
What I came up with was to explicitly refresh the credentials versus get them lazily when I created a DynamoDb object for instance. Here's the function I use which returns a promise & resolves when the credentials are refreshed.
refresh: function() {
var deferred = $q.defer();
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: COGNITO_IDENTITY_POOL_ID,
IdentityId: COGNITO_ID,
Logins: 'cognito-identity.amazonaws.com'
});
AWS.config.credentials.refresh(function(error) {
if ((error === undefined) || (error === null)) {
$log.debug("Credentials Refreshed Success: ", AWS.config.credentials);
var params = {
region: 'us-east-1',
apiVersion: '2012-08-10',
credentials: AWS.config.credentials
};
$rootScope.dynamodb = new AWS.DynamoDB({params: params});
deferred.resolve();
}
else {
$log.debug("Error refreshing AWS Creds:, ", error);
deferred.reject(error);
}
});
return deferred.promise;
}
If you want to use Cognito credentials to call other AWS services, I recommend you use the high-level AWS.CognitoIdentityCredentials object from the Javascript SDK, instead of calling the service API directly.
You can find more information about how to initialize and use AWS.CognitoIdentityCredentials in the Cognito Developer Guide:
Developer Authenticated Identities
Albert
The flow is like this: You ask the CognitoIdentityCredentials for a IdentityId, the IDentityId is supposed to track users accross devices and across Identities providers like (Facebook, Google, TWitter, etc.) then you with that ID you ask for a role attached to your pole CognitoIdentity, after you get the token, you ask the STS.assumeRoleWithWebIdentity for a temporary credentials with the appropriate roles attached to your pole.
Here is an example of how I did it:
// set the Amazon Cognito region
AWS.config.region = 'us-east-1';
// initialize the Credentials object with our parameters
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:YMIDENTITYPOLEID',
});
// We can set the get method of the Credentials object to retrieve
// the unique identifier for the end user (identityId) once the provider
// has refreshed itself
AWS.config.credentials.get(function(err) {
if (err) {
console.log("Error: "+err);
return;
}
console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);
params = {
IdentityId: AWS.config.credentials.identityId
}
// Other service clients will automatically use the Cognito Credentials provider
// configured in the JavaScript SDK.
// Get the Role associated with the id coming from the pool
var cognitoidentity = new AWS.CognitoIdentity();
cognitoidentity.getOpenIdToken(params, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
}else{
// Get temporoarly credientials form STS to access the API
var params = {
RoleArn: 'ROLE_OF_YOUR_POLE_ARN', /* required */
RoleSessionName: 'WHATEVERNAME', /* required */
WebIdentityToken: data.Token, /* required */
};
var sts = new AWS.STS()
console.log(data); // successful response
console.log(data.Token)
sts.assumeRoleWithWebIdentity(params, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
}else{
console.log(data); // successful response
// Now we need these credentials that we got for this app and for this user
// From here we can limit the damage by
// Burst calling to the API Gateway will be limited since we now that this is a single user on a single device
// If suspicious activities we can drop this user/device
// The privileges are limited since the role attached to this is only the API GateWay calling
// This creds are temporary they will expire in 1h
var apigClient = apigClientFactory.newClient({
accessKey: data.Credentials.AccessKeyId,
secretKey: data.Credentials.SecretAccessKey,
sessionToken: data.Credentials.Token, //OPTIONAL: If you are using temporary credentials you must include the session token
region: AWS.config.region // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1
});
// Call the get to test
apigClient.deviceGet({}, {})
.then(function(result){
//This is where you would put a success callback
console.log(result)
}).catch( function(result){
//This is where you would put an error callback
});
}
});
}
});
});
NB: This was a test to get access to the API Gateway service, but it is not different to get access to other services, it depends on the pole you configure it and its attached services.
If you have credential for a user created in IAM you don't need the temporary token, but if you use this flow you have to include it.
Another point, limit the access to the services on your pole, keep in mind that is a publicly given key, every one can use it to get access to your stuff.
STS.assumeRoleWithWebIdentity is used because we are on the web, in the AWS JS SDK, if you use iOS or android/java or Boto, you have to use STS.assumeRole.
Hope this helps.