My serverless.yml looks like this -
service: books-api-v1
provider:
name: aws
region: eu-west-1
role: arn:aws:iam::298945683355:role/lambda-vpc-role
runtime: nodejs8.10
iamRoleStatements:
- Effect: Allow
Action:
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
Resource: "*"
functions:
login:
handler: api/controllers/authController.authenticate
vpc: ${self:custom.vpc}
events:
- http:
path: /v1/users/login
method: post
cors: true
And the actual API function looks this -
'use strict';
var db = require('../../config/db'),
crypt = require('../../helper/crypt.js'),
jwt = require('jsonwebtoken');
exports.authenticate = function(event, context, callback) {
console.log(JSON.parse(event.body));
const data = IsJsonString(event.body) ? JSON.parse(event.body) : event.body;
let myEmailBuff = new Buffer(process.env.EMAIL_ENCRYPTION_KEY);
db.users.find({
where:{
username : crypt.encrypt(data.username)
}
}).then(function(user) {
try {
let res = {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({
message:'ERROR!',
success: false
})
};
if (!user) {
res.body = JSON.stringify({
success: false,
message: 'Authentication failed. User not found.',
authFail:true
});
//res.status(200).json({ success: false, message: 'Authentication failed. User not found.',authFail:true, });
}else if (user) {
// check if password matches
if (crypt.decrypt(user.password) != data.password) {
res.body = JSON.stringify({
success: false,
message: 'Authentication failed. Wrong password.',
authFail:true
});
//res.status(200).json({ success: false, message: 'Authentication failed. Wrong password.',authFail:true, });
} else {
// if user is found and password is right
// create a token with only our given payload
// we don't want to pass in the entire user since that has the password
const payload = {
username: crypt.decrypt(user.username)
};
var token = jwt.sign(payload, process.env.JWT_SIGINING_KEY, {
algorithm: process.env.JWT_ALGORITHM,
expiresIn: 18000,
issuer: process.env.JWT_ISS
});
// return the information including token as JSON
// res.status(200).json({
// success: true,
// message: 'Enjoy your token!',
// token: token
// });
res.body = JSON.stringify({
success: true,
message: 'Enjoy your token!',
token: token
});
}
//callback(null, res);
}
console.log(res);
callback(null, res);
} catch (error) {
console.log('errorsssss: ');
console.log(error);
}
});
};
function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
Works very well on my serverless local, but when I try it on AWS Lambda function, then it gives "Internal server error" Message.
I have looked into my cloudwatch logs and the response looks correct to me. Here is the response that I am sending back to callback.
{
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true
},
body: '{"success":true,"message":"Enjoy your token!","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNhaW1hLm5hc2lyckBnbWFpbC5jb20iLCJpYXQiOjE1NDUwNjE4OTYsImV4cCI6MTU0NTA3OTg5NiwiaXNzIjoiaWFtbm90YWdlZWsuY28udWsifQ.2HyA-wpmkrmbvrYlWOG41W-ezuLCNQnt0Tvrnsy2n3I"}'
}
Any help please?
In this case, it might because of the Api Gateway configurations. Does your api public? Because I have met such problems when the api is not public.
Related
I am looking to connect my Lambda with my Step Function, and cannot figure out why it will not startExecution.
SDK Code:
import AWS from "aws-sdk";
const stepfunctions = new AWS.StepFunctions({ apiVersion: "2016-11-23" });
interface Params {
stateMachineArn: string;
input: string;
}
export async function handler(event: any, context: object) {
console.log("event.body", event.body);
const params: Params = {
stateMachineArn: process.env.STEP_FUNCTION_ARN,
input: JSON.stringify(event.body),
name: "testNameField",
};
console.log("PARAMS", params);
stepfunctions.startExecution(params, (err: any, data: any) => {
if (err) {
console.log("THERE WAS AN ERROR", err);
console.log("ERROR STACK", err.stack);
} // an error occurred
else {
console.log("data", data);
} // successful response
});
}
Permissions:
Allow: states:DeleteStateMachine
Allow: states:StartExecution
Allow: states:CreateStateMachine
Allow: states:SendTaskSuccess
Allow: states:DeleteActivity
Allow: states:SendTaskHeartbeat
Allow: states:CreateActivity
Allow: states:SendTaskFailure
Allow: states:StopExecution
Allow: states:GetActivityTask
Allow: states:UpdateStateMachine
Allow: states:StartSyncExecution
Extra information:
I have tried doing a "test" on the console for the lambda function,
from which it succeeds. I'm not sure where else to look.
In the step function, all the columns
(Total/Running/Succeeded/Failed/Timed out/Aborted) are 0.
The params console.log offers the correct information
Are there any error messages outputted from the console.log?
Solution Code:
const AWS = require("aws-sdk");
AWS.config.update({ region: "eu-west-1" });
const stepFunction = new AWS.StepFunctions();
interface Params {
stateMachineArn: string;
input: string;
name: string;
}
exports.handler = async (event: any) => {
console.log(event);
const stepFunctionParams = {
stateMachineArn: process.env.STEP_FUNCTION_ARN,
input: JSON.stringify({
message: event.body,
}),
name: "name" + String(Date.now()),
};
try {
const stepFunctionResponse = await stepFunction
.startExecution(stepFunctionParams)
.promise();
return { statusCode: 200, body: "Success" };
} catch (e) {
console.log("Problem executing SF :", JSON.stringify(e));
return {
statusCode: 500,
body: "Problem executing step function : " + JSON.stringify(e),
headers: { "Access-Control-Allow-Origin": "*" },
};
}
};
I'm trying to know how to use cookies with AWS-Lambda with the serverless framework as per this blogpost
and following is my serverless.yml code
functions:
hello:
handler: handler.hello
events:
- http:
path: /post
method: post
cors:
origin : 'https://xyz.netlify.app'
and Lambda function as per following
"use strict";
const cookie = require("cookie");
module.exports.hello = async (event) => {
const body = JSON.parse(event.body);
const name = body.name;
const value = body.value;
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "https://xyz.netlify.app",
"Access-Control-Allow-Credentials": true,
"Set-Cookie": cookie.serialize(name, value, {
expires: new Date(new Date().getTime() + 10 * 1000),
}),
},
body: JSON.stringify(
{
input: event,
},
null,
2
),
};
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
As you can notice, I already have configured the code to avoid any cors issue.
While try to send a post request as per following,
const name = document.getElementById('name')
const value = document.getElementById('value')
const post_btn = document.getElementById('post_btn')
post_btn.addEventListener('click', () => {
console.log(name.value, value.value)
const post_url = 'https://abcdxyz59t9.execute-api.ap-south-1.amazonaws.com/dev/post'
const user = {
name: name.value,
value: value.value
};
// request options
const options = {
method: 'POST',
body: JSON.stringify(user),
headers: {
'Content-Type': 'application/json'
}
}
// send POST request
fetch(post_url, options)
.then(res => res.json())
.then(res => console.log(res));
})
I do get a Set-Cookie header like below
But the cookie doesn't get saved in the browser.
That's not the case when I directly try to hit a get request with that URL without the cors in the browser. Can anyone please tell me what to do?
list:
handler: todos/list.list
events:
- http:
path: todos
method: 'use strict'
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: "StreamData",
Item: {
ID: uuid.v1(),
name: data.name,
description: data.description,
price: data.price,
imageURL: data.imageURL }, };
module.exports.list = (event, context, callback) => { dynamoDb.scan(params, (error, result) => { if (error) { console.error(error); callback(null, { statusCode: error.statusCode || 501,
headers: {
'Content-Type': 'text/plain' },
body: 'Couldn\'t fetch the todos.', });
return; }
const response = {
statusCode: 200, b
ody: JSON.stringify(result.Items), };
callback(null, response); }); };
cors: true
I am new to yaml having a issue with line 10 TableName: "StreamData", says "bad mapping"if I remove the line the error moves up or down to the following line.
The code you had written is not a YAML code. YAML is a declarative language and it does not contain commas(,) and semi-colons(;). Also, the YAML language does not use the equals symbol(=) for declaration. It only uses colons(:).
See YAML syntax here: https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
Been browsing through SO for the past hours to find a fix for my issue, but no progress yet, I'm getting
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Now typically, this could be fixed with adding appropriate headers to the code, and it would work, however it's not the case for me, since I've tried to configure cors through API Gateway on AWS.
Screenshot:
Some research on google mentioned, that if the function is using lambda proxy integration, we would have to modify the lambda itself, and add the headers by our own, e.g
headers: {
'Access-Control-Allow-Origin': '*',
},
However this doesn't make much difference, is there anything I'm missing?
My actual code for the lambda (forgot to add):
const rp = require('request-promise')
const sendEmail = require('./sendEmail')
module.exports.run = async (event, context, callback) => {
const body = JSON.parse(event.body)
const { name, email, budget, message, attachment } = body
if (!name) {
return callback(null, {
statusCode: 400,
body: JSON.stringify({ message: 'Name is required' }),
})
}
if (!email) {
return callback(null, {
statusCode: 400,
body: JSON.stringify({ message: 'Email address is required' }),
})
}
if (!message) {
return callback(null, {
statusCode: 400,
body: JSON.stringify({ message: 'Message is required' }),
})
}
return Promise.all([
sendEmail({
to: 'Example <user#example.com>',
subject: 'New enquiry received!',
data:
`Name: ${name}\n` +
`Email: ${email}\n` +
`Budget: ${budget || 'n/a'}\n` +
`Attachment: ${attachment || 'n/a'}\n` +
`\n${message}`,
}),
sendEmail({
to: `${name} <${email}>`,
subject: 'Your message was delivered at ',
data:
'Thanks for reaching out!\n' +
'Somebody at our office will get back to you as soon as possible.\n' +
'\n' +
'While you wait, check out our Handbook (/) and get acquainted with how we do things around here.\n' +
'We have a lot of content there so feel free to explore as you please.\n' +
'\n' +
'Speak soon,\n' +
'\n',
}),
rp({
method: 'POST',
uri: `https://hooks.slack.com/services/${process.env.SLACK_PATH}`,
json: true,
body: {
text: `<!channel> New enquiry received`,
attachments: [
{
fallback: 'Information:',
pretext: 'Information:',
color: '#FF5050',
fields: [
{ title: 'Name', value: name, short: false },
{ title: 'Email', value: email, short: false },
{ title: 'Budget', value: budget || 'n/a', short: false },
{ title: 'Attachment', value: attachment || 'n/a', short: false },
{ title: 'Message', value: message || 'n/a', short: false },
],
},
],
},
}),
])
.then(() => {
return callback(null, {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({ message: 'Great success' }),
})
})
.catch(err => {
return callback(null, {
statusCode: 500,
body: JSON.stringify({
message: 'Oh no :( Message not delivered',
error: err
}),
})
})
}
No 'Access-Control-Allow-Origin' header is present on the requested resource.
This is saying that the resource you requested, your Lambda via API Gateway, is not returning an Access-Control-Allow-Origin header in its response; the browser is expecting the CORS headers in the response from the API (possibly because of an OPTIONS request), but the response doesn’t have them.
To solve your issue, add a Access-Control-Allow-Origin: * header to the response your Lambda returns. Using the first item you're returning:
if (!name) {
return callback(null, {
statusCode: 400,
headers: {
'Access-Control-Allow-Origin': '*',
// any other required headers
},
body: JSON.stringify({ message: 'Name is required' }),
})
}
Worth noting that you'll have to add those headers to every response.
I'm using Bell for Meetup OAuth, then persisting with hapi-auth-cookie.
Here are the relevant parts of code.
server.auth.strategy('session', 'cookie', {
cookie: 'sessionid',
password: '32_char_password',
// redirectTo: '/login', //this causes a loop immediately after allowing access
redirectTo: false,
isSecure: false,
});
server.auth.strategy('meetupauth', 'bell', {
provider: 'meetup',
password: '32_char_password',
isSecure: false,
providerParams: {
set_mobile: 'on'
},
clientId: 'client_id',
clientSecret: 'client_secret',
});
server.route({
method: ['GET'],
path: '/login',
config: {
auth: 'meetupauth',
handler: (request, reply) => {
request.cookieAuth.set({
sid: request.auth.credentials.profile
});
return reply.redirect('/user');
}
}
});
server.route({
method: 'GET',
path: '/user',
config: {
auth: 'session',
handler: (request, reply) => reply('My Account'),
}
});
The code works fine, except immediately after allowing access to Meetup. Once allowed access, the /login page redirects to /user. Not redirecting back to the login page, I get a 401, and after I reload /user the cookie is there. Once I've given access, it works fine; just the initial allow. What is happening?
Try setting the "isSameSite" variable to the "Lax" value
const options = {
connections: {
state: {
isSameSite: 'Lax'
}
}
};
const server = new Server(options);