Post Confirmation ConfirmForgotPassword lambda execution returns InvalidLambdaResponseException - Unrecognizable lambda output - authentication

I have spent a bunch of hours to solve this issue, all related SO answers seem to be outdated or irrelevant.
State:
Amplify.js "^4.3.10" with code
Auth.forgotPasswordSubmit(email, confirmationCode, password)
.then(_ => this.notification.success("Confirmation OK"))
.catch(err => console.log(err));
Lambda on Node.js 14
Cognito trigger "Post confirmation"
Lambda function code:
'use strict';
exports.handler = async (event, context, callback) => {
if (event.triggerSource === "PostConfirmation_ConfirmForgotPassword") {
const postConfirmEmail = () => `<html><body>HERE IS MY TEMPLATE</body></html>`;
event.response = {
emailSubject: "Reset Password Notification",
emailMessage: postConfirmEmail()
};
callback(null, event);
}
};
As result, I am getting
InvalidLambdaResponseException: Unrecognizable lambda output (Error 400)
The thing is that password is really updating as expected, but e-mail confirmation is NOT sent and error remains.
TIP: User is CONFIRMED. Tried also with "context.done(null, event);" / "return event;" but response is always with the same error.

You shouldn't be using an async handler with the callback. It's either one or the other.
Simply return event without calling the callback or don't make your function async.
Additionally, Cognito will not send confirmation emails, you will have to implement this functionality yourself.

Related

Set cookie after fetch request response from auth server

I just started learnign about the express library, im developing an app that access restricted info about a user using an Eve Online API, to do this the user is redirected to an authentication page to get an access and refresh token.
Everything works fine until I try to pull the 'refresh_token' from the response and set a cookie with it.
The error:
(node:20600) UnhandledPromiseRejectionWarning: TypeError: res.cookie is not a function
My code:
const url = 'https://login.eveonline.com/v2/oauth/token';
const options = {
'method':'POST',
headers:
{
'authorization':'Basic '+ process.env.ENV_PASS,
'Content-Type':'application/x-www-form-urlencoded',
'host':'login.eveonline.com'
},
body:''
}
function send_get_request(req, res){
options.body =`grant_type=authorization_code&code=${req.query.code}`
fetch(url,options,{credentials:'include'})
.then(handle_stream)
.then(handle_json)
.then(set_cookie)
.then(redirect_home)
}
function handle_stream(res){
return res.json() //handless data stream, returns responce
}
function handle_json(res){
return res.refresh_token
}
function set_cookie(res){
return res.cookie('refresh_token','hello')
}
function redirect_home(res){
res.redirect('http://localhost:3000/home')
}
router.get('/',send_get_request)
I tried breaking the .then() block but still res.cookie doesn't exits. Also tried using credentials but it doesn't work.
Your code contains two variables res: One stands for the response that your middleware sends back to the client, the other stands for the response you are receiving from the fetch operation. Only the handle_stream function operates on the latter, whereas set_cookie and redirect_home operate on the former.
The last three function are also synchronous and need not be chained with .then. The are invoked synchronously in a function that takes as parameter the json which handle_stream produces asynchronously.
function send_get_request(req, res){
options.body =`grant_type=authorization_code&code=${req.query.code}`;
fetch(url,options,{credentials:'include'})
.then(handle_stream)
.then(function(json) {
var refresh_token = handle_json(json);
set_cookie(res, refresh_token);
redirect_home(res);
});
}
It is all perhaps easier to understand with the async-await syntax:
async function send_get_request(req, res){
options.body =`grant_type=authorization_code&code=${req.query.code}`;
var response = await fetch(url,options,{credentials:'include'});
var json = await handle_stream(response);
var refresh_token = handle_json(json);
set_cookie(res, refresh_token);
redirect_home(res);
}

Why does my API code return "You are not subscribed to this API." even with the "X-RapidAPI-Key"?

I am trying to execute the an API which I found on rapidapi.com.
The url of the API is https://rapidapi.com/sheharyar566/api/random-words5/?utm_source=ANIA-KUBOW&utm_medium=DevRel&utm_campaign=DevRel.
I copied the code from the site which includes the "X-RapidAPI-Key" value when you are logged in.
But when I execute the code on node, I get the message "You are not subscribed to this API."
How do I get it to return the correct result, which is a randomly generated word?
Below is the code:
import fetch from 'node-fetch';
const options = {
method: "GET",
headers: {
"X-RapidAPI-Key": "KEY-GOES-HERE",
"X-RapidAPI-Host": "random-words5.p.rapidapi.com",
},
};
fetch(
"https://random-words5.p.rapidapi.com/getMultipleRandom?count=5&wordLength=5",
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.error(err));
And below is the error message:
{ message: 'You are not subscribed to this API.' }
As the error message states, you are not subscribed to the API. RapidAPI supports 3 tiers of subscriptions:
Free
Freemium
Paid
On free APIs, the subscription will be auto-created on the first call. For freemium and paid, you will need to navigate the plans tab and select the right plan for you.
In your case, go to https://rapidapi.com/sheharyar566/api/random-words5/pricing and select one of the plans.

express middleware not sending response

I have a delete route that has 2 middleware functions Authcontroller.protect and authcontroller.restrictTo("admin, "lead-guide")
router
.delete(
authController.protect,
authController.restrictTo("admin", "lead-guide"),
tourController.deleteTour
);
Within restrictTo I have a check to see if the user has the proper "role" to perform that task and if they don't, express is supposed ot send a 403. I'm seeing that express never actually sends the response. it enters the if statement(i see the console successfully printing fialure) and then it just skips sending the response.
exports.restrictTo = (...roles) => {
return (req, res, next) => {
console.log(req.user.role);
if (!roles.includes(req.user.role)) {
console.log("failure");
return res.status(403).json({
status: fail,
message: "you do not have permission to perform this action"
});
console.log(req, res);
}
next();
};
};
Put a try/catch in your inner function and see if there's an exception being thrown.
From looking at your code, if the fail variable (which you don't show a definition for) is not defined, then that would throw an exception and keep the res.json() from executing.

How to prevent dynamicLink listener from firing multiple times in react-native?

I have enabled signInWithEmailLink() from firebase in my react-native app.
Everything works successfully, the user is also created but the I think the onLink(handleLink) listener is fired multiple times and leads to an error even after user sign-in.
Logs:
link is tru
LOG email: email#gmail.com //I have hidden the actual email
LOG email: email#gmail.com
LOG email: email#gmail.com
LOG USer created
LOG EROR: [Error: [auth/invalid-action-code] The out of band code is invalid. This can happen if the code is malformed, expired, or has already been used.]
LOG EROR: [Error: [auth/invalid-action-code] The out of band code is invalid. This can happen if the code is malformed, expired, or has already been used.]
LOG EROR: [Error: [auth/invalid-action-code] The out of band code is invalid. This can happen if the code is malformed, expired, or has already been used.]
As you can see its fired multiple times, how can I prevent this??
This is my code:
const handleLink = async link => {
console.log('opened Link: ', link.url);
if (auth().isSignInWithEmailLink(link.url)) {
console.log('link is tru');
try {
const email = await AsyncStorage.getItem('email');
console.log('email: ', email);
await auth()
.signInWithEmailLink(`${email}`, link.url)
.then(() => {
console.log('USer created');
})
.catch(err => {
console.log('EROR: ', err);
});
} catch (err) {
console.log('err: ', err);
}
} else {
console.log('link is false');
}
};
const link = dynamicLinks().onLink(handleLink);
Help would be very much appreciated
Since console.log('email: ', email); is called 3 times, i assume that console.log('link is tru'); is also called 3 times, so the problem is that the whole handleLink function is called 3 times before auth().signInWithEmailLink finishes.
I ran into the same issue here is the answer.
Email link Authentication has a longer expiration time (around 6 hours). If you'll create 2 or more sign in emails in a row, you should be able to login with the latest link being received. You'll also be able to receive an error message for example in iOS, "The action code is invalid. This can happen if the code is malformed, expired, or has already been used" when you clicked the older links.

AWS Cognito JS SDK returning "AdminUpdateUserAttributes is not a function" error message

I'm trying to create a function which allows me to update a user's phone number in a Cognito User Pool. The code is in a NodeJS application, using the latest aws-sdk library.
I have this function callback structure working for a number of other actions against the user pool, e.g. creating and listing users, updating MFA, etc. So I am confident there's nothing structurally wrong with the way I have laid the code out.
But for this particular function, I am receiving an error that says AdminUpdateUserAttributes "is not a function".
I've tried changing different attributes in case it's a phone number thing, but I got the same result.
function cognitoUpdatePhone(username, phoneNumber, callback) {
var params = {
UserPoolId: '<my pool Id>',
Username: username,
UserAttributes: {
phone_number: phoneNumber
}
};
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
cognitoidentityserviceprovider.AdminUpdateUserAttributes(params, function (err, data) {
if (err) {
callback(err, false);
}
else {
callback(null, true);
}
});
}
I'm getting following response from the server. The stack trace indicates the source of the error is: aws-sdk/lib/state_machine.js
message: 'cognitoidentityserviceprovider.AdminUpdateUserAttributes is not a function',
code: 'TypeError',
Encountered the exact same problem. Solved it by changing the first letter of the function to lowercase: adminUpdateUserAttributes
Try using this:
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});