Cognito adminDeleteUser user pool does not exist error - javascript

Why does the AWS Cognito adminDeleteUser function as shown in the code below give a "User pool does not exist" error message?
const aws = require('aws-sdk');
aws.config.accessKeyId = 'aaaaaaa';
aws.config.secretAccessKey = 'sssssss';
aws.config.region = 'us-west-2';
const CognitoIdentityServiceProvider = new
aws.CognitoIdentityServiceProvider();
global.fetch = require('node-fetch');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
// this section of code produces a correct userPool object
let poolData =
{
UserPoolId: 'ppppppp',
ClientId: 'ccccccc'
};
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
console.log('userPool: ', userPool);
// this section of code reports error: "ResourceNotFoundException:
User pool ppppppp does not exist."
let params =
{
UserPoolId: 'ppppppp',
Username: 'nnnnnnn'
};
CognitoIdentityServiceProvider.adminDeleteUser(params, (err,data) =>
{
if (err) console.log(err);
else console.log('user deleted');
});

Problem has been resolved by changing code from
aws.config.accessKeyId = 'aaaaaaa';
aws.config.secretAccessKey = 'sssssss';
aws.config.region = 'us-west-2';
to the following
aws.config.update(
{
accessKeyId: 'aaaaaaa',
secretAccessKey: 'sssssss',
region: 'us-west-2'
});
Note also that the following code creates a userPool object whether or not a valid UserPoolId value is provided:
let poolData =
{
UserPoolId: 'ppppppp,
ClientId: 'ccccccc'
};
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);

Related

Unable to access CognitoIdentityServiceProvider with credentials after user logged in

I'm currently using this package amazon-cognito-identity-js to login my user using cognito user pool
import { Config, CognitoIdentityCredentials, CognitoIdentityServiceProvider } from "aws-sdk";
import {
CognitoUser,
CognitoUserPool,
AuthenticationDetails,
CognitoRefreshToken,
} from "amazon-cognito-identity-js";
const region = this.options.REGION
const userPoolId = this.options.USER_POOL_ID // user pool id of User Pool
const clientId = this.options.CLIENT_ID // client id of app client
const identityPoolId = this.options.IDENTITY_POOL_ID // identify pool id of federated identity pool
let authenticationData = { Username: params.username, Password: params.password }
let authenticationDetails = new AuthenticationDetails(authenticationData)
let poolData = {
UserPoolId: userPoolId,
ClientId: clientId
}
let userPool = new CognitoUserPool(poolData)
let userData = {
Username: params.username,
Pool: userPool
}
let cognitoUser = new CognitoUser(userData)
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken()
var logins = {}
logins['cognito-idp.' + region + '.amazonaws.com/' + userPoolId] = accessToken
const credentials = new CognitoIdentityCredentials({
region: region,
IdentityPoolId: identityPoolId,
Logins: logins
})
// **** IM GETTING AN ERROR HERE IN CognitoIdentityServiceProvider ****
var cognitoIdentityProvider = new CognitoIdentityServiceProvider({
apiVersion: '2016-04-18',
region: region,
credentials: credentials
});
var params = {
GroupName: 'STB',
UserPoolId: userPoolId,
};
cognitoIdentityProvider.listUsersInGroup(params, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
},
onFailure: function(err) {
console.log(err)
}
})
I'm able to login successfully but I'm getting an error when calling listUsersInGroup function
CredentialsError: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
I also checked that the credentials returns
console.log(credentials)
> CognitoIdentityCredentials {expired: true, expireTime: null, refreshCallbacks: Array(0), accessKeyId: undefined, sessionToken: undefined, …}
What am I missing here? I checked that it's possible to pass credentials instead of AccessKey and Secret according to this documentation

PassportJS JWT: protected-route is Unauthorized in my browser , but Authorized on Postman

I'm trying to implement JWT authentication, and I can't figure out why in Postman protected-route is available, while in my browser protected-route is Unauthorized.
I'm a beginner and its first time implementing jwt authentication in my project following this tutorial https://www.youtube.com/playlist?list=PLYQSCk-qyTW2ewJ05f_GKHtTIzjynDgjK
Problem
/login and /register work fine and I can see from the log they issue a JWT token in the req.headers
like 'Authorization':'Bearer <token>', however when I try to access GET /protected-route in my browser, it returns Unauthorized, and I can see no logging from JWTStrategy.
I think req.headers.Authorization is not set to all HTTP requests in the app, but only to POST /login, /register routes So my questions are:
Is this req.headers["Authorization"] = 'Bearer <toekn>'; correct way to set req headers to all GET and POST request in the app?
Does the jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken() checks for Authorization property in req.headers or res.headers?
I have provided the relevant code snippets please have a look!
Code:
app.js
//...
require('./config/database'); // require the db
// ...
const passport = require('passport');
const strategy = require('./config/passport').strategy;
// ...
app.use(passport.initialize());
passport.use(strategy);
// ...
module.exports = app
router/index.js
const router = express.Router();
//...
const User = require('../config/database').User;
const passport = require('passport');
const utils = require('../lib/utils');
// register route
router.post('/register', function(req, res, next){
const saltHash = utils.genPassword(req.body.password);
console.log("req.body.password is: " + req.body.password)
const salt = saltHash.salt;
const hash = saltHash.hash;
const newUser = new User({
username: req.body.username,
hash: hash,
salt: salt
})
newUser.save()
.then((user) => {
const jwt = utils.issueJWT(user);
if (jwt){
req.headers["Authorization"] = jwt.token;
}
res.redirect('/login')
})
.catch(err => next(err))
});
// login route
router.post('/login', function(req, res, next){
User.findOne({username: req.body.username})
.then((user) => {
if(!user) {
res.status(401).json({success: false, msg: "Could not find user "})
}
// validate the user
const isValid = utils.validPassword(req.body.password, user.hash, user.salt)
if(isValid) {
// issue a JWT
const jwt = utils.issueJWT(user);
if (jwt){
req.headers["Authorization"] = jwt.token;
}
res.redirect("/")
} else {
res.status(401).json({success: false, msg: "you entered the wrong password"})
}
})
.catch(err => next(err))
});
// GET protected route
router.get("/protectd-route", passport.authenticate('jwt', {session: false}), async (req, res, next) => {
res.render("user/getuser.pug")
next()
})
passport.js
const User = require('../config/database').User;
// ...
const Strategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
/// PUB_KEY
const pathToKey = path.join(__dirname, '..', 'id_rsa_pub.pem');
const PUB_KEY = fs.readFileSync(pathToKey, 'utf8');
// options
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: PUB_KEY,
algorithms: ['RS256']
};
// strategy
const strategy = new Strategy(options, (payload, done) => {
User.findOne({_id: payload.sub})
.then((user) => {
if(user) {
return done(null, user)
} else {
return done(null, false)
}
})
.catch((err) => done(err, null))
});
module.exports.strategy = strategy;
utils.js
genPassword() - Creating a salt and hash out of it to store in db
validPassword() - re-hashing user salt and hash to verify
issueJWT() - signing user with jsonwebtoken
const crypto = require('crypto');
const jsonwebtoken = require('jsonwebtoken');
const User = require('../config/database').User;
//...
const pathToKey = path.join(__dirname, '..', 'id_rsa_priv.pem');
const PRIV_KEY = fs.readFileSync(pathToKey, 'utf8');
// validate in /login
function validPassword(password, hash, salt) {
var hashVerify = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return hash === hashVerify;
}
// generate in /register
function genPassword(password) {
var salt = crypto.randomBytes(32).toString('hex');
var genHash = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return {
salt: salt,
hash: genHash
};
}
// sign
function issueJWT(user) {
const _id = user._id;
const expiresIn = '86400';
const payload = {
sub: _id,
iat: Date.now()
};
const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, { expiresIn: expiresIn, algorithm: 'RS256' });
return {
token: "Bearer " + signedToken,
expires: expiresIn
}
}
module.exports.validPassword = validPassword;
module.exports.genPassword = genPassword;
module.exports.issueJWT = issueJWT;
Postman
In Postman, the protected route is showing successfully, with Headers set as above.
The browser network is showing this, there is no Authorization property both in response and request headers
Clearly, I'm missing something, but I can't figure it out. Any help is appreciated
here is also my db
database.js
const uri = process.env.MONGO_URI
const connection = mongoose.connection;
mongoose.connect(uri, {
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000
})
connection.on('error', console.error.bind(console, "connection error"))
connection.once('open', () => {
console.log('MongoDB database connection has been established successfully')
})
const userSchema = new mongoose.Schema({
username: String,
hash: String,
salt: String
});
const User = mongoose.model('User', userSchema )
module.exports.User = User;

how to get awstoken from AWS cognito

I want to use accessToken variable outside the success function. I tried different ways to use variable but it didn't work.
var authenticationData = {
Username : 'username',
Password : 'password',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = { UserPoolId : 'us-east-1_ExaMPle',
ClientId : '1example23456789'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username : 'username',
Pool : userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
/* Use the idToken for Logins Map when Federating User Pools with identity pools or when passing through an Authorization Header to an API Gateway Authorizer */
var idToken = result.idToken.jwtToken;
},
onFailure: function(err) {
alert(err);
},
});
Why not add the accessToken to the authenticationData object?
var authenticationData = {
Username : 'username',
Password : 'password',
AccessToken : ''
};
// And then set the token in the success method:
authenticationData.AccessToken = result.getAccessToken().getJwtToken();
Once authenticationData.AccessToken has been set, you can use the value anywhere in scope.

Refactored AWS S3 Uploader to reusable code doesn't invoke uploader

Consider the Controller :
authControoler:
const mongoose = require('mongoose');
const User = mongoose.model("User");
const crypto = require('crypto');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { JWT_SECRET } = require('../config/keys');
const AWS = require('aws-sdk');
const multer = require("multer");
const multerS3 = require("multer-s3");
const uuid = require('uuid');
const s3 = new AWS.S3({
accessKeyId: process.env.AWS_ACCESS_KEY,
secretAccessKey: process.env.AWS_SECRET_KEY,
region: process.env.AWS_REGION,
});
const uuid_name = uuid.v4();
const signUpUploader = multer({
storage: multerS3({
s3: s3,
bucket: process.env.AWS_S3_BUCKET_NAME,
metadata: function (req, file, cb) {
console.log("Uploading file to S3...");
cb(null, {
OriginalFileName: file.originalname.toLowerCase(),
RandomName: uuid_name,
});
},
key: function (req, file, cb) {
cb(null, file.originalname);
}
})
}).single('singleFile');
exports.signUp = async (req, res, next) => {
// call the uploader to AWS S3
signUpUploader(req, res, function (err) {
if (err) {
// An error occurred when uploading
console.log('Something went wrong :', err);
return;
}
// Everything went fine
console.log('Everything went fine');
const image_s3_url = req.file.location;
const { name, email, password } = req.body;
if (!email || !password || !name) {
return res.status(422).json({ error: "please add all the fields" })
}
// update User in Mongo ...
});
};
I've refactored the code into reusable aws code , as follows :
aws.js:
const AWS = require('aws-sdk');
const multer = require("multer");
const multerS3 = require("multer-s3");
const uuid = require('uuid');
const uuid_name = uuid.v4();
const s3 = new AWS.S3({
accessKeyId: process.env.AWS_ACCESS_KEY,
secretAccessKey: process.env.AWS_SECRET_KEY,
region: process.env.AWS_REGION,
});
module.exports = class AWSUtils {
constructor(filePropertyName) {
this.filePropertyName = filePropertyName;
}
getFilePropertyName() {
return this.filePropertyName;
}
uploadImage() {
const signUpUploader = multer({
storage: multerS3({
s3: s3,
bucket: process.env.AWS_S3_BUCKET_NAME,
metadata: function (req, file, cb) {
console.log("Uploading file to S3...");
cb(null, {
OriginalFileName: file.originalname.toLowerCase(),
RandomName: uuid_name,
});
},
key: function (req, file, cb) {
cb(null, file.originalname);
}
})
}).single(this.filePropertyName);
return signUpUploader;
}
}
authControoler:
const mongoose = require('mongoose');
const User = mongoose.model("User");
const crypto = require('crypto');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { JWT_SECRET } = require('../config/keys');
const AWSUtils = require('../utils/aws');
const _utils = new AWSUtils('singleFile');
exports.signUp = async (req, res, next) => {
console.log('In signUp');
// call the uploader to AWS S3
_utils.uploadImage(req, res, function (err) { // Refactored !!!
if (err) {
// An error occurred when uploading
console.log('Something went wrong :', err);
return;
}
// Everything went fine
console.log('Everything went fine');
const image_s3_url = req.file.location;
const { name, email, password } = req.body;
if (!email || !password || !name) {
return res.status(422).json({ error: "please add all the fields" })
}
// update User in Mongo ...
});
};
After refactored and extracted out the AWS code into its own file (aws.js) , I call uploadImage however nothing happens , no error , no upload , nothing.
What am I missing here ?
multer returns an Express middleware function. In the original code, that middleware function was assigned directly to signUpUploader
In your refactored code, the _util.uploadImage function is actually returning the middleware function, but in your code, you're not using the result as middleware, instead trying to use _util.uploadImage.
There are a few options, but a quick fix would be to do something like this:
Replace:
_utils.uploadImage(req, res, function (err) {
// The function body
})
With:
const signUpUploader = _utils.uploadImage();
signUpUploader(req, res, function (err) {
// The function body
})
That will use the mutler middleware the way you are expecting.

Dialogflow function deployment issues on Node.js/Firebase

I am trying to send user SMS texts to Dialogflow in a Firebase function, however I'm receiving the following error when I deploy my functions. The code for Dialogflow was copied off the DF Node.js library.
error Move function declaration to function body root
This is referring to async function dialogflowMessage() line. Maybe I don't fully understand async/await yet, but it seems like my function needs to be nested within the original receive SMS function. Below is my complete function code for handling incoming texts, checking if SMS, and sending to DF.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({ origin: true});
const serviceAccount = require('./service-account.json'); //firebase service account
const serviceKey = require('./service-key.json'); //Dialogflow service key
const express = require('express');
const async = require('async');
const http = require('http');
const bodyParser = require('body-parser');
const accountSid = 'REDACTED'; //Twilio acct sid
const authToken = 'REDACTED'; //Twilio auth token
const twilioNumber = '+REDACTED'; //Twilio phone number
const client = require('twilio')(accountSid, authToken);
const MessagingResponse = require('twilio').twiml.MessagingResponse;
const dialogflow = require('dialogflow');
const uuid = require('uuid');
const {Storage} = require('#google-cloud/storage');
exports.processMsg = functions.https.onRequest((request, response) => {
const twiml = new MessagingResponse();
const sid = request.body.MessageSid;
const body = request.body.Body;
if (sid.startsWith('SM', 0)) {
//Start Dialogflow
async function dialogflowMessage(projectId = 'REDACTED-PROJECT-ID') {
// A unique identifier for the given session
const sessionId = uuid.v4();
// Create a new session
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: body,
// The language used by the client (en-US)
languageCode: 'en-US',
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
}
//end Dialogflow
} else if (sid.startsWith('MM', 0)) {
twiml.message(`This is an image!! ${media}`);
} else {
twiml.message(
'No Body param match, Twilio sends this in the request to your server.'
);
}
response.writeHead(200, {'Content-Type': 'text/xml'});
response.end(twiml.toString());
});
exports.processMsg = functions.https.onRequest((request, response) => {
const twiml = new MessagingResponse();
const sid = request.body.MessageSid;
const body = request.body.Body;
if (sid.startsWith('SM', 0)) {
dialogflowMessage('REDACTED-PROJECT-ID')
} else if (sid.startsWith('MM', 0)) {
twiml.message(`This is an image!! ${media}`);
} else {
twiml.message(
'No Body param match, Twilio sends this in the request to your server.'
);
}
async function dialogflowMessage(projectId = 'REDACTED-PROJECT-ID') {
// A unique identifier for the given session
const sessionId = uuid.v4();
// Create a new session
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: body,
// The language used by the client (en-US)
languageCode: 'en-US',
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
}
response.writeHead(200, {'Content-Type': 'text/xml'});
response.end(twiml.toString());
});

Categories