How to get session callback info? AWS - Cognito - JavaScript - amazon-web-services

I am trying to get the AccessKeyID and the SecretKey (ultimately to programatically input into a CRUD operation on dynamoDB with fine grained access control).
Anywho, there are many API calls to get the credentials like getCredentialsForIdentity(). However, these all require further params, which requires more api requests and more params and so on.
Ive found a way to log a Cognito user in, and then check if they are logged in on for a profile page, where it can display the email and username:
var data = {
UserPoolId : _config.cognito.userPoolId,
ClientId : _config.cognito.clientId
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
window.onload = function(){
if (cognitoUser != null) {
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
return;
}
console.log('session validity: ' + session.isValid());
console.log(session.Credentials.AccessKeyId); //<--THIS DOESNT WORK
cognitoUser.getUserAttributes(function(err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
document.getElementById("email_value").innerHTML = result[2].getValue();
document.getElementById("username").innerHTML = cognitoUser.getUsername();
});
});
}
}
console.log(session.Credentials.AccessKeyId); seems to be an invalid request. Im assuming there's some good callback info in the session, like the AccessKeyID and SecretKey, which is what I'm looking for.

session.Credentials.AccessKeyId will not work since session's output is:
e {idToken: t, refreshToken: e, accessToken: t, clockDrift: 0}
whereas AWS.config.credentials's output is:
Thus your code will be:
var data = {
UserPoolId : _config.cognito.userPoolId,
ClientId : _config.cognito.clientId
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
window.onload = function(){
if (cognitoUser != null) {
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
return;
}
console.log('session validity: ' + session.isValid());
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: _config.cognito.IdentityPoolId
});
AWS.config.credentials.get(function(err) {
console.log(AWS.config.credentials); // * see above what your response will be
console.log(AWS.config.credentials.accessKeyId);
console.log(AWS.config.credentials.secretAccessKey);
});
}
}

Related

Cognito authorizing a user through AWS lambda function

I use AWS Cognito and need to authorize a user through a lambda function. I have seen examples online and when I try to apply them, the Cognito authentication does not run and gets somehow skipped:
const AWS = require('aws-sdk');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
global.fetch = require("node-fetch");
const CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool;
var AuthenticationDetails = AmazonCognitoIdentity.AuthenticationDetails;
var CognitoUser = AmazonCognitoIdentity.CognitoUser;
var USER_POOL_ID = 'my_pool_id';
var CLIENT_ID = 'my_client_id';
var idToken = '';
exports.handler = async (event, callback) => {
var email = event['username'];
var password = event['password'];
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
Username: email,
Password: password
});
const poolData = {
UserPoolId: USER_POOL_ID,
ClientId: CLIENT_ID
};
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username: email,
Pool: userPool
}
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
var accessToken = result.getAccessToken().getJwtToken();
console.log(result);
console.log(accessToken);
idToken = result.idToken.jwtToken;
console.log(idToken);
callback(null, accessToken);
},
onFailure: (err) => {
console.log(err);
idToken = err;
callback(err);
},
});
console.log("cognitoUser after: ", cognitoUser);
};
I can see the last console.log printed in the logs, but lambda does not seem to wait for the request resolution of cognitoUser.authenticateUser, as none of the console.logs inside onSuccess or onFailure get printed.
Here are couple of options
Remove async from exports.handler = async (event, callback).
Keep async and wrap authenticateUser as Promise and use await
const res = await new Promise((resolve, reject) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
var accessToken = result.getAccessToken().getJwtToken();
console.log(result);
console.log(accessToken);
idToken = result.idToken.jwtToken;
console.log(idToken);
resolve(accessToken);
},
onFailure: (err) => {
console.log(err);
idToken = err;
reject(err);
},
});
}
Note: Code has not been tested.

Cognito User Pools is returning null user object

Folks, I am getting similar error where my getCurrentUser is returning null. I think, I partially know the reason for the same.
<script type="text/javascript" src="https://sdk.amazonaws.com/js/aws-sdk-2.7.16.min.js" ></script>
<script type="text/javascript" src="/web/amazon-cognito-identity.js"></script>
<script type="text/javascript" src="/web/aws-cognito-sdk.js"></script>
import * as AWSCognito from 'amazon-cognito-identity';
const region = 'us-east-1';
const docClient = createDynamoDbClient();
function createDynamoDbClient() {
AWS.config.update({
region: "us-east-1", endpoint: 'https://dynamodb.us-east-1.amazonaws.com'});
userAuth();
return new AWS.DynamoDB();
}
function userAuth() {
var data = {
UserPoolId: '***********',
ClientId: '************'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
try {
if (cognitoUser != null)
{
cognitoUser.getSession(function(err, session)
{
if (err) {
console.log(err);
return;
}
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials(
{
IdentityPoolId : 'us-east-1:********',
Logins : {
"cognito-idp.us-east-1.amazonaws.com/us-east-1_*******": session.getIdToken().getJwtToken()
}
});
AWS.config.credentials.get(function(err) {
if (!err)
{
console.log("In try block 4");
var id = AWS.config.credentials.identityId;
console.log('Cognito Identity ID '+ id);
var docClient = new AWS.DynamoDB.DocumentClient(
{
region: AWS.config.region
}
);
var params =
{
TableName: 'VideoInfo',
Item:{
keyName:kN,
technicalMetadata:tM
}
};
docClient.put(
params,
function(err, data) {
if (err){
console.error(err);
}else
{
console.log(data);
}
}
);
}
});
});
}
else {
console.log(cognitoUser);
return;
}
} catch (e) {
console.log(e);
return;
}
}
I am getting the below error essentially which is causing the complete issue.
TypeError: root.AWSCognito is undefined
ReferenceError: AmazonCognitoIdentity is not defined
Possible, it means I am not getting AWSCognito object itself using which I can get the correct UserPool and ending up with null user.
Spent a lot of time on this today and really appreciate if someone can help on the same!
enter image description here

Local storage is missing an ID Token, Please authenticate error while changing password Cognito AWS

I am building an application. In that Sign up, Signin and other operations are working fine. But, when I try to change password using following code, it says
"Local storage is missing an ID Token, Please authenticate"
Code is:
changePassword(mail: any) {
var that = this;
var userPool = new CognitoUserPool(this.poolData);
var userData: any = {
Username: mail,
Pool: userPool
};
var cognitoUser = new CognitoUser(userData);
// To get the session
cognitoUser.getSession(function (err, session) {
if (err) {
alert(err);
return;
}
var userPool = new CognitoUserPool(that.poolData);
var userData: any = {
Username: mail,
Pool: userPool
};
var cognitoUser = new CognitoUser(userData);
var oldp = prompt('Please input old password ', '');
var newp = prompt('Please input new password ', '');
cognitoUser.changePassword(oldp, newp, function (err, result) {
if (err) {
alert(err.message || JSON.stringify(err));
return;
}
alert("Password successfully changed...");
});
});
}
I am not sure what is wrong in this. Please help me solve this.
Thank you...
After so much of struggle, I figured out that I was creating new Cognito user every time using
poolData = {
UserPoolId: "XXXXXXXXXXXXXXXXX",
ClientId: "XXXXXXXXXXXXXXXXXXXXXXXX"
};
userPool: CognitoUserPool = new CognitoUserPool(this.poolData);
So, whenever I call this, a new cognito-user is created. So, change-password on this was not working.
When I created a common function to access cognitoUser and using the same everywhere worked for me.
Thank you...

Token received in lambda function returns Unauthorized in APIG

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.

Express Passport unable to get facebook friends list

When attempting to use the Facebook api to get the friends list of a verified account it seems to work except that the friends list returned is empty.
facebook.js
var https = require('https');
exports.getFbData = function(accessToken, apiPath, callback) {
var options = {
host: 'graph.facebook.com',
port: 443,
path: apiPath + '?access_token=' + accessToken, //apiPath example: '/me/friends'
method: 'GET'
};
var buffer = ''; //this buffer will be populated with the chunks of the data received from facebook
var request = https.get(options, function(result){
result.setEncoding('utf8');
result.on('data', function(chunk){
buffer += chunk;
});
result.on('end', function(){
callback(buffer);
});
});
request.on('error', function(e){
console.log('error from facebook.getFbData: ' + e.message)
});
request.end();
}
app.js
app.get('/', function (req, res) {
if (req.session.myID != null && req.session.myName != null) {
User.findOne({sessionID: req.session.myID, username: req.session.myName}, function (err, doc) {
if (err) {throw err}
else if (doc != null) {
facebook.getFbData(doc.facebookToken, '/me/friends', function(data){
console.log(data);
res.render('index');
});
}
else {
//console.log("not logged in");
res.render('index');
}
});
}
else {
//console.log("not logged in");
res.render('index');
}
});
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET',
callbackURL: "http://localhost:3000/auth/facebook/callback",
profileFields: ['id', 'displayName']
},
function(accessToken, refreshToken, profile, done) {
User.findOne(..., function(err, user) {
if (err) { return done(err); }
user.facebookID = profile.id;
user.facebookToken = accessToken;
user.save();
return done(null, user);
});
}
));
app.get('/auth/facebook', passport.authenticate('facebook',
{scope: 'user_friends'})
);
app.get('/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/');
}
);
The console.log in the facebook.getFbData callback prints:
{"data":[]}
This code actually works correctly. However it does not fetch the whole friends list, only the list of friends who also have the app.