AWS cognito: getCredentials not working - node.js

Im in the process of learning to use AWS Cognito. I have set up a userpool and a identity pool.
Code (simplified):
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
let cognitoGetUser = userPool.getCurrentUser();
if (cognitoGetUser != null) {
cognitoGetUser.getSession((err, result) => {
if (result) {
console.log ("Authenticated to Cognito User and Identity Pools!");
let token = result.getIdToken().getJwtToken();
let cognitoParams = {
IdentityPoolId: this.identityPool,
Logins: {}
};
cognitoParams.Logins["cognito-idp.eu-west-1.amazonaws.com/"+this.poolData.UserPoolId] = token;
AWS.config.credentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.getCredentials(() => {
console.log(AWS.config.credentials.accessKeyId)
console.log(AWS.config.credentials.secretAccessKey)
console.log(AWS.config.credentials.sessionToken)
}
}
}
}
},
onFailure: function(err) {
console.log('error');
console.log(err)
}
}
}
Most of the code works as expected: The authenticateUser fires the onSuccess and I can see a jwt token ect
Problem: I cant get the AWS.config.getCredentials to work. It executed without any errors, but accessKeyId, secretAccessKey and SessionToken are all undefined.
Any suggestions to what I'm doing wrong?

I cant get the AWS.config.getCredentials to work. It executed without any errors but,
This may be a mistaken assumption. Your abbreviated code is missing a couple of closing parentheses, but ran fine for me without any meaningful adjustments.
When calling getCredentials, any errors are "silently" reported through an error object. I would think you'd see a 400 response somewhere (network tab or console or both), but getCredentials() doesn't really report errors in a visible fashion by itself.
To see what is going wrong, you should add a parameter to the callback you pass to getCredentials():
AWS.config.getCredentials((err) => {
if (err) {
console.log(err);
} else {
console.log(AWS.config.credentials.accessKeyId)
console.log(AWS.config.credentials.secretAccessKey)
console.log(AWS.config.credentials.sessionToken)
}
});
For reference, one commonly encountered error object looks like this. Note that the useful message is found in originalError.message:
{
"message": "Could not load credentials from CognitoIdentityCredentials",
"code": "CredentialsError",
"time": "2018-06-03T15:19:02.078Z",
"requestId": "71b03b4a-6741-11e8-98af-b70a114474f8",
"statusCode": 400,
"retryable": false,
"retryDelay": 94.28032122526344,
"originalError": {
"message": "Invalid login token. Issuer doesn't match providerName",
"code": "NotAuthorizedException",
"time": "2018-06-03T15:19:02.078Z",
"requestId": "71b03b4a-6741-11e8-98af-b70a114474f8",
"statusCode": 400,
"retryable": false,
"retryDelay": 94.28032122526344
}
}
The corresponding 400 in the Network tab contains this response:
{"__type":"NotAuthorizedException","message":"Invalid login token. Issuer doesn't match providerName"}

Related

NodeJS cannot import custom module although it exists

Note: What you see below is the updated description of my problem, because I have been going down a rabbit hole and finding the root cause of a problem.
So, I found what's causing it (read 'OLD DESCRIPTION' below to know the context), but I have zero idea why is it being caused. So, the thing is, apparently Node cannot find the utils.getHash function (I have a separate file called utils.js which exports the getHash function), so it is never called, and execution never moves forward.
utils.js
...
const getHash = (password) => {
return crypto.createHash('sha3-512').update(password).digest('hex')
}
...
module.exports = {
getHash: getHash
}
Someone help please :(
OLD DESCRIPTION
There's a weird problem I am facing. I wrote a backend API server in ExpressJS, and one of the task it performs is user authentication. I am using MongoDB as the database, and Mongoose to connect and perform operations on it.
The problem I am facing is that the checkUserCreds function does not proceed after a point (commented in code), and Express just returns a blank JSON response.
And I say it it's weird, because I tested with the SAME code just 2 days back, it worked correctly like it should.
user.js
userSchema.statics.checkUserCreds = function (email, password) {
return new Promise((resolve, reject) => {
// Execution goes upto '$and' line, then it goes nowhere; no exceptions are raised
User.findOne({
$and: [{ email: email }, { password: utils.getHash(password) }]
}, (err, userDoc) => {
if (err) {
reject({ status: "ERROR", message: err })
} else if (userDoc) { // If valid credential
console.log(`User with email '${email}' logged in`)
resolve({ status: "OK", message: "Login successful!" })
} else { // If invalid credential
reject({ status: "ERROR", message: "Invalid credential!" })
}
})
})
}
api.js
// Route - Login (POST: email, password)
router.post("/login", (req, res) => {
// If user is already logged in, reject further login
if (req.session.email) {
res.json({ status: "ERROR", message: "Already logged in!" }).status(403).end()
} else {
// Get data from body
var form = formidable()
form.parse(req, (err, fields, files) => {
if (err) {
res.json({ status: "ERROR", message: err }).status(500).end()
} else {
// Check if credentials are valid
User.checkUserCreds(fields.email, fields.password).then((result) => {
// This portion of code isn't reached either
req.session.email = fields.email
res.json(result).status(200).end()
}).catch((err) => {
res.json(err).status(401).end()
})
}
})
}
})
Can anyone tell me why this is happening?

How to fix TypeError: Cannot read property 'post' of undefined on Axios with Nestjs cronjob

I tried using cron scheduler to get authentication token every 15 sec(Test purpose) the cron is supposed to call the auth endpoint but I got Exception has occurred: TypeError: Cannot read property 'post' of undefined
#Cron(CronExpression.EVERY_15_SECONDS)
async handleCron() {
//const Primetimeauth = this.PrimetimeAuth()
const primeAuth = await this.httpService.post('https://clients.com/api/auth', {
"username": process.env.username,
"password": process.env.password
}).toPromise();
if (primeAuth.status != 200) {
throw new HttpException({
message: `Vending Authentication Failed`,
statusCode: primeAuth.status
}, HttpStatus.BAD_REQUEST);
}
const data = primeAuth.data;
await this.PrimetimeAuthToken.updateOne({ "_id": "3dtgf1341662c133f0db71412drt" }, {
"$set":
{
token: data.token,
tokenExpirationTime: data.expires,
timeTokenReceived: new Date
}
});
return data;
}
Cron expressions do not work with Request scoped providers, due to possibly being run outside of the context of the request. Due to this, all dependencies come in as undefined. To fix this, you'll need a non-request-scoped provider.

Azure BotBuilder - How to get the user information of the OAuth Connection Settings

I've created a Azure Web App Bot and added a OAuth Connection Setting which takes the user to Salesforce. Everything works well, I'm able to authenticate the user through my bot and also, I can get the access token from Salesforce.
Problem
Can someone help me to get the user information from Salesforce? Because, I am able to get the access token alone and not sure, how to get the user id from Salesforce.
I've written the below code,
var salesforce = {};
salesforce.signin = (connector, session, callback) => {
builder.OAuthCard.create(connector,
session,
connectionName,
"Sign in to your Salesforce account",
"Sign in",
(createSignInErr, createSignInRes) => {
if (createSignInErr) {
callback({
status: 'failure',
data: createSignInErr.message
});
return;
}
callback({
status: 'success',
data: createSignInRes
});
});
};
salesforce.getUserToken = (connector, session, callback) => {
connector.getUserToken(session.message.address,
connectionName,
undefined,
(userTokenErr, userTokenResponse) => {
if (userTokenErr) {
callback({
status: 'failure',
data: userTokenErr.message
});
return;
}
callback({
status: 'success',
data: userTokenResponse
});
});
};
salesforce.accessToken = (connector, session, callback) => {
salesforce.getUserToken(connector, session, (userTokenResponse) => {
if (userTokenResponse.status == 'failure') {
// If the user token is failed, then trigger the sign in card to the user.
salesforce.signin(connector, session, (signinResponse) => {
// If the sign in is failed, then let the user know about it.
if (signinResponse.status == 'failure') {
session.send('Something went wrong, ', signinResponse.message);
return;
}
// If the sign in is success then get the user token and send it to the user.
salesforce.getUserToken(connector, session, (newUserTokenResponse) => {
if (newUserTokenResponse.status == 'failure') {
session.send('Something went wrong, ', newUserTokenResponse.message);
return;
}
callback(newUserTokenResponse);
return;
});
});
}
callback(userTokenResponse);
});
};
I can get the userTokenResponse here. But I need Salesforce user id so that I can start interacting with Salesforce behalf of the user.
If you have only OAuth access token you may query details about the user by invoking http GET against:
https://login.salesforce.com/services/oauth2/userinfo for PROD or
https://test.salesforce.com/services/oauth2/userinfo for sandbox
Add only Authorization: Bearer Y0UR0AUTHTOKEN to the header of the http GET request.
Based on my recent test the result returned from the server looks like:
{
"sub": "https://test.salesforce.com/id/[organizationid]/[userId]",
"user_id": "000",
"organization_id": "000",
"preferred_username": "me#mycompany.com",
"nickname": "myNick",
"name": "name lastname",
"urls": {
...
},
"active": true,
"user_type": "STANDARD",
...
}
You don't need a userId to get the user information where an accessToken is enough. I've installed jsforce and used the below code to get the identity information.
Solved by doing,
const jsforce = require('jsforce');
var connection = new jsforce.Connection({
instanceUrl: instanceUrl,
sessionId: accessToken
});
connection.identity((error, response) => {
if(error) {
callback({
status: 'failure',
message: error.message
});
return;
}
callback({
staus: 'success',
data: response
});
});

How to access dataset of an identity in cognito federated identities from lambda

Let me start with the overall description of what I'm trying to achieve. I'm building a serverless API using Lambda, Cognito (Federated Identities), API Gateway etc. I'm using aws_iam as the authorizer in API Gateway. In some endpoints, I need to access for example user e-mail or username or whatever so I can send it back in the response (also data of users who did not make the request). I guess I'm looking for some kind of "admin" access to the identity pool so I can retrieve data based on cognitoIdentityId.
Now in my case, this data is stored in a dataset in Cognito. The question is, how can I access this data from my Lambda function (node.js)? Is this a good approach at all? Should I use something else instead of datasets? Is there a working example somewhere?
I will be happy to provide more details if necessary.
Thanks
EDIT #1:
here is the code of my lambda function:
module.exports.getDataSet = (event, context, callback) => {
console.log("event: " + JSON.stringify(event));
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IDENTITY_POOL_ID
});
try {
AWS.config.credentials.get(function() {
var client = new AWS.CognitoSync();
var params = {
DatasetName: 'userinfo',
IdentityId: event.requestContext.identity.cognitoIdentityId,
IdentityPoolId: IDENTITY_POOL_ID
};
client.listRecords(params, function (err, data) {
if (err) {
console.log(JSON.stringify(err));
} else {
console.log(data);
}
});
});
} catch (ex) {
callback(ex);
}
};
and this is what i get in err when calling listRecords:
{
"message": "Missing credentials in config",
"code": "CredentialsError",
"time": "2017-05-26T08:42:39.298Z",
"requestId": "46712a9b-41ef-11e7-9e3c-074afafb3349",
"statusCode": 400,
"retryable": false,
"retryDelay": 21.688148977111666,
"originalError": {
"message": "Could not load credentials from CognitoIdentityCredentials",
"code": "CredentialsError",
"time": "2017-05-26T08:42:39.298Z",
"requestId": "46712a9b-41ef-11e7-9e3c-074afafb3349",
"statusCode": 400,
"retryable": false,
"retryDelay": 21.688148977111666,
"originalError": {
"message": "Unauthenticated access is not supported for this identity pool.",
"code": "NotAuthorizedException",
"time": "2017-05-26T08:42:39.298Z",
"requestId": "46712a9b-41ef-11e7-9e3c-074afafb3349",
"statusCode": 400,
"retryable": false,
"retryDelay": 21.688148977111666
}
}
}
EDIT #2:
solved by removing
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IDENTITY_POOL_ID
});
from the code and adding the AmazonCognitoReadOnly policy to the role that invokes the lambda.
First, you need the Cognito identity of the caller to be known to the Lambda function. The request context in API Gateway includes the Cognito id, which you can put into the payload that is sent to the Lambda function, or use the Lambda proxy integration and have it included automatically.
Once you have the Cognito id in the Lambda, you can use it to retrieve an associated dataset from Cognito Sync. You can use an IAM policy like AmazonCognitoReadOnly to give your Lambda function permission to call the ListRecords API on Cognito Sync (which gives you access to the dataset).

Magento Soap cart.info isn't working for all carts

I am having a node application and I need a few informations about a shopping cart from a magento customer. So I wrote myself a little test script to test the results of the soap api (I am using magento to help me communication with the soap interface).
var MagentoAPI = require('magento');
var magento = new MagentoAPI({
host: '192.168.73.45',
port: 80,
path: '/magento/api/xmlrpc/',
login: 'dev',
pass: '123456'
});
magento.login(function(err, sessId) {
if (err) {
console.log(err);
return;
}
magento.checkoutCart.info({ quoteId: 696 }, magentoCallback);
});
function magentoCallback(err,response) {
if (err) {
return console.log(err);
}
console.log("Result: ");
console.log(response)
}
This script works fine. If I use some old quote ids (which are in the database from the sample data) I get a good result, but if I use an shopping cart from an user I created, then I get the following error:
{
"original": {
"message": "Unknown XML-RPC tag 'BR'",
"name": "Error"
},
"name": "Magento Error",
"message": "An error occurred while calling cart.info"
}

Resources