How can I configure cors to run lambda function locally
I have tried different ways but not able to get proper solution.
Below is my template.yml
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: dev
Cors:
AllowHeaders: "'Content-Type,Authorization,Origin,X-Requested-With,Accept,x-id-token,x-custom-header'"
AllowOrigin: "'*'"
AllowMethods: "'OPTIONS,POST,GET,PUT,DELETE'"
AllowCredentials: "'*'"
Auth:
AddDefaultAuthorizerToCorsPreflight: False
DefaultAuthorizer: MyLambdaTokenAuthorizer
Authorizers:
MyLambdaTokenAuthorizer:
FunctionArn: !GetAtt MyAuthFunction.Arn
HelloFunction:
Type: AWS::Serverless::Function
Properties:
Handler: functions/hello/handler.hello
CodeUri: "."
Events:
HelloAPI:
Type: Api
Properties:
Path: /hello
Method: GET
RestApiId: !Ref MyApi
And this is my handler function
exports.hello = async (event) => {
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Content-Type": "application/json",
"Access-Control-Allow-Credentials": true, // Required for cookies, authorization headers with HTTPS
},
body: JSON.stringify({ message: "Hello World!" }),
};
callback(null, response);
};
still getting error:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Going to answer this question for future reference due to really bad AWS documentation on API Gateway for CORS. Having battled with this shite for nearly three days, the end result is as follows.
First, in the AWS::Serverless::Api segment in your SAM template, configure CORS, for example:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Cors:
AllowHeaders: "'*'"
AllowOrigin: "'*'"
AllowCredentials: "'*'"
AllowMethods: "'*'"
Next, create a stupid, dummy lambda to handle any OPTIONS request, make sure this lambda sets the headers on the response. Something like this:
export const handler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
return {
headers: {
"Access-Control-Allow-Origin" : "*", // Required for CORS support to work
"Access-Control-Allow-Headers" : "*", // Required for CORS support to work
"Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
},
statusCode: 200
};
}
Finally, in your SAM template, collect all the endpoints and point them to this stupid lambda.
OptionHandler:
Type: AWS::Serverless::Function
Properties:
Handler: <lambda above>
Runtime: nodejs14.x
Architectures:
- arm64
Timeout: 2
Events:
Method1APIOptions:
Type: Api
Properties:
Path: /path/{param}
Method: options
RestApiId:
Ref: ApiGatewayApi
Method2APIOptions:
Type: Api
Properties:
Path: /path2/{param}
Method: options
RestApiId:
Ref: ApiGatewayApi
Method3APIOptions:
Type: Api
Properties:
Path: /path3/{params}
Method: options
RestApiId:
Ref: ApiGatewayApi
Now every time you deploy this API using sam deploy, CORS will not be messed up.
try this:
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: dev
Cors:
AllowOrigin: "'*'"
AllowHeaders: "'*'"
Auth:
AddDefaultAuthorizerToCorsPreflight: False
DefaultAuthorizer: MyLambdaTokenAuthorizer
Authorizers:
MyLambdaTokenAuthorizer:
FunctionArn: !GetAtt MyAuthFunction.Arn
HelloFunction:
Type: AWS::Serverless::Function
Properties:
Handler: functions/hello/handler.hello
CodeUri: "."
Events:
HelloAPI:
Type: Api
Properties:
Path: /hello
Method: get
RestApiId: !Ref MyApi
HelloAPIOptions:
Type: Api
Properties:
Path: /hello
Method: options
RestApiId: !Ref MyApi
I changed the cores policies and added a endpoint for OPTIONS /hello.
Related
I'm trying to use Strict-Transport-Security header with API Gateway on swagger definition, but I keep getting Invalid mapping expression parameter specified: method.response.header.Strict-Transport-Security when I use:
x-amazon-apigateway-integration:
responses:
default:
statusCode: "200"
responseParameters:
method.response.header.Strict-Transport-Security: "'max-age=31536000; includeSubdomains; preload'"
Full definition below:
openapi: 3.0.1
info:
title:APIs
version: 1.0.1
servers:
- url: "http://localhost:9001"
security:
- ApiGateway: []
paths:
/user/{id}:
get:
summary: Get user
parameters:
- in: path
name: id
required: true
schema:
type: string
format: uuid
description: return user by ID
responses:
"200":
description: user returned successfully
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
description: Validation failure
"500":
description: Something went wrong
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${apiLambda.Arn}/invocations
responses:
default:
statusCode: "200"
responseParameters:
method.response.header.Strict-Transport-Security: "'max-age=31536000; includeSubdomains; preload'"
passthroughBehavior: "never"
httpMethod: "POST"
type: "aws_proxy"
/user:
post:
summary: Create user
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/User"
responses:
"200":
description: User created successfully
"400":
description: Validation failure
"500":
description: Something went wrong
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${apiLambda.Arn}/invocations
responses:
default:
statusCode: "200"
passthroughBehavior: "never"
httpMethod: "POST"
type: "aws_proxy"
components:
securitySchemes:
ApiGateway:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
User:
type: object
required:
- id
- name
properties:
id:
type: string
format: uuid
example: "317d0a1d-1a44-4a47-b2d8-cbe64665591c"
description: "user ID"
name:
type: string
example: "Josiah Morrow"
description: "User name"
minimum: 1
maximum: 50
Unable to put integration response on 'GET' for resource at path '/user/{id}': Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression parameter specified: method.response.header.Strict-Transport-Security]
I have configured a serverless function as below
id:
handler: id.get
events:
- http:
path: id
method: get
cors:
origin: ""
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- x-access-token
allowCredentials: true
Code in my handler function is as below
let headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': event.headers.Origin ? event.headers.Origin : event.headers.origin,
'Access-Control-Allow-Credentials': true
}
callback(null, {
"isBase64Encoded": false,
"statusCode": 200,
"headers": headers,
"body": JSON.stringify(body),
"multiValueHeaders": multiValueHeaders
})
I am getting response to OPTIONS request as
access-control-allow-origin: *
access-control-allow-credentials: true
Due to that I am getting the below error
Access to XMLHttpRequest at 'https://example.com/dev/id' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I want the Access-Control-Allow-Origin should be dynamic(origin of the request), How can I fix the issue?
I have created a new method options with the below code
module.exports.options = async (event, context, callback) => {
const origin = event.headers.Origin || event.headers.origin;
context.succeed({
headers: {
"Access-Control-Allow-Headers": "Accept,Accept-Language,Content-Language,Content-Type,Authorization,x-correlation-id,x-access-token",
"Access-Control-Allow-Methods": "GET,HEAD,OPTIONS",
"Access-Control-Allow-Origin": origin ? origin : '*',
"Access-Control-Allow-Credentials": true
},
statusCode: 204
});
};
serverless.yml
options:
handler: id.options
events:
- http:
path: id
method: options
Change to this config:
id:
handler: id.get
events:
- http:
path: id
method: get
cors:
origin: "*"
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- x-access-token
allowCredentials: true
i created lambda function and api (get method) then i mapped them and deploy.
api-url:https://**********.execute-api.*********.amazonaws.com/test when i open this url i got below output.
{"statusCode": 200, "headers": {"Content-Type": "application/json"}, "body": "{\"message\": \"new subject area added successfully\"}"}
lambda function:
import json
def lambda_handler(event, context):
message={
'message':'new subject area added successfully'
}
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps(message)
}
Ajax call :
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
function addSubjectArea() {
alert("going to call ajax");
$.ajax({
url: 'https://37l42zsugg.execute-api.us-east-1.amazonaws.com/test',
type: 'GET',
crossDomain: true,
contentType: 'application/json',
success:function(response){
alert(response)
},
error: function (jqXHR, textStatus, errorThrown) {
alert("error occurred while get data");
}
});
}
$(document).ready(function(){
addSubjectArea();
});
</script>
</head>
<body>
<div id="div1"><h2>api call from ajax methoid</h2></div>
</body>
</html>
but from ajax call it is going to enter into error section
case-2 :
my cloudFormation-template:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
hello
Sample SAM Template for hello
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.6
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello2
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
####
api Resource is generated successfully and when tried to enable cors.
few things going to fail why?
any suggestions?
thanks.
I can't figure out what's wrong on my Authorization.
I've a Hello function which only returns a simple a static message. If I deploy without set "Authorizer", it works. I've tested on Postman. The issue starts when I try adding Authorizer.
I've my Cognito fully working. On my front end I can sign up, then do a login and then get the Token from this login session.
When I go to Postman and test, I'm always getting "unauthorized" as answers.
On Postman I test on GET method, on "Headers" tab I added "Authorization" attribute and pasted on value the token that I've from Login session. I also tested this on the value field the prefix "bearer" as some places recommended. No success.
I've been trying for the past week solve this issue. Please, any help will be extremely useful.
serverless.yml
provider:
name: aws
runtime: nodejs10.x
stage: dev
region: eu-west-1
environment:
MY_TABLE: ${self:custom.myStage}_${self:custom.settings.tb_items}
MY_STAGE: ${self:custom.myStage}
MY_DOMAIN: ${self:custom.myDomain}
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:GetItem"
- "dynamodb:PutItem"
- "dynamodb:UpdateItem"
- "dynamodb:DeleteItem"
- "dynamodb:Scan"
Resource: "*"
functions:
hello:
handler: ${self:custom.pathFunc}/phraseOption.hello
events:
- http:
method: GET
path: hello
cors: true
integration: lambda-proxy
authorizer:
type: COGNITO_USER_POOLS
authorizerId:
Ref: ApiGatewayAuthorizer
resources:
Resources:
CognitoUserPool:
Type: "AWS::Cognito::UserPool"
DeletionPolicy: Retain
Properties:
MfaConfiguration: OFF
UserPoolName: ${self:custom.myStage}_aePool
EmailVerificationSubject: 'Your verification Code'
EmailVerificationMessage: 'Use this code to confirm your sign up {####}'
AutoVerifiedAttributes:
- email
UsernameAttributes:
- email
Policies:
PasswordPolicy:
MinimumLength: 6
RequireLowercase: False
RequireNumbers: False
RequireSymbols: False
RequireUppercase: False
CognitoUserPoolClient:
Type: "AWS::Cognito::UserPoolClient"
DeletionPolicy: Retain
Properties:
ClientName: ${self:custom.myStage}_aePoolClient
GenerateSecret: False
UserPoolId:
Ref: CognitoUserPool
ApiGatewayAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoUserPool
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
RestApiId:
Ref: ApiGatewayRestApi
ProviderARNs:
- Fn::GetAtt:
- CognitoUserPool
- Arn
phraseOptions.js
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Your function executed successfully!',
input: event,
}),
};
callback(null, response);
};
I can see the function was created with the correct Auth:
Also Authorizer create as expected (I guess)
Swagger
---
swagger: "2.0"
info:
version: "2019-10-07T21:24:17Z"
title: "XXXXXX"
host: "XXXXXX"
basePath: "/dev"
schemes:
- "https"
paths:
/getPhrase:
get:
responses: {}
options:
consumes:
- "application/json"
produces:
- "application/json"
responses:
200:
description: "200 response"
headers:
Access-Control-Allow-Origin:
type: "string"
Access-Control-Allow-Methods:
type: "string"
Access-Control-Allow-Credentials:
type: "string"
Access-Control-Allow-Headers:
type: "string"
/hello:
get:
responses: {}
security:
- CognitoUserPool: []
/item:
post:
responses: {}
options:
consumes:
- "application/json"
produces:
- "application/json"
responses:
200:
description: "200 response"
headers:
Access-Control-Allow-Origin:
type: "string"
Access-Control-Allow-Methods:
type: "string"
Access-Control-Allow-Credentials:
type: "string"
Access-Control-Allow-Headers:
type: "string"
/item/{itemId}:
get:
responses: {}
put:
responses: {}
delete:
responses: {}
options:
consumes:
- "application/json"
produces:
- "application/json"
responses:
200:
description: "200 response"
headers:
Access-Control-Allow-Origin:
type: "string"
Access-Control-Allow-Methods:
type: "string"
Access-Control-Allow-Credentials:
type: "string"
Access-Control-Allow-Headers:
type: "string"
/items:
get:
responses: {}
options:
consumes:
- "application/json"
produces:
- "application/json"
responses:
200:
description: "200 response"
headers:
Access-Control-Allow-Origin:
type: "string"
Access-Control-Allow-Methods:
type: "string"
Access-Control-Allow-Credentials:
type: "string"
Access-Control-Allow-Headers:
type: "string"
securityDefinitions:
CognitoUserPool:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "cognito_user_pools"
I've figure out what was wrong!
The server side was Ok. The issue on testing it on Postman was the Token.
I was using "cognitoUser.signInUserSession.accessToken.jwtToken", but supposed to be "cognitoUser.signInUserSession.idToken.jwtToken".
Everything working as expected now.
Help me please. What have I done wrong. I want to have access to ec2 via api gataway and wrote a cloudformation template
paths:
/{proxy+}:
x-amazon-apigateway-any-method:
headers:
Access-Control-Allow-Headers:
type: "string"
Access-Control-Allow-Methods:
type: "string"
Access-Control-Allow-Origin:
type: "string"
Content-Type:
type: "string"
authority:
type: "string"
produces:
- "application/json"
parameters:
- name: "proxy"
in: "path"
required: false
type: "string"
responses: {}
x-amazon-apigateway-integration:
responses:
default:
statusCode: "200"
uri: "http://ec2-1111111111.eu-west-1.compute.amazonaws.com/{proxy}"
requestParameters:
integration.request.header.Content-Type: "'text/html'"
"integration.request.path.proxy": "method.request.path.proxy"
passthroughBehavior: "when_no_match"
httpMethod: ANY
type: "http_proxy
for this where I defined 1 endpoint http_proxy. When I test this endpoint everything works fine, but as soon as I deploy api and try to get access through the browser, error 404 crashes
After removing and redeploying the stack, I achieved the page display, but still I can’t ensure that the connected css files are connected correctly.