Missing Authentication Token Error with CloudFront & API Gateway - amazon-web-services

I have setup a CloudFront Distribution with an API Gateway as one of the origins and this API Gateway is configured with an AWS IAM authorizer.
When CloudFront url is invoked with Authorization headers, it returns a 403 error.
{
"message": "Missing Authentication Token"
}
However, when the API Gateway url is invoked instead of CloudFront url with the same Authorization headers, it worked.
I've also tried invoking the endpoint without any authorizer via CloudFront url and it worked. Any idea on how to solve this issue.

When provisioning a CloudFront distribution, remember that CloudFront removes most headers from the request by default.
This is done to optimize the cache hit ratio while preventing your origin server from making decisions based on those headers that would not be appropriate for different requests based on other variations (or absence) of those headers, which CloudFront would then serve from cache, inappropriately.
You'll need to whitelist the Authorization header for forwarding to the origin.
Note also that when provisioning API Gateway behind a CloudFront distribution that you control, you'll probably want to deploy your API endpoint as regional and not edge-optimized.

Please see below, in case if anyone is facing this issue when using API Gateway as a secondary origin - behavior instead of default behavior for the Cloudfront Distribution i.e.
forwarding all paths like /api/* requests to API Gateway
serving the remaining paths with an s3 or other default resource like an Application load balancer
I was using AWS CDK to define and deploy AWS API Gateway as a secondary behavior and faced the same issue and I did everything including
forwarding headers and query params
enabling all http request methods
Setting the API gateway as regional
My configuration for the deployment is as follows:
originConfigs: [{
customOriginSource: {
domainName: clientAppBucket.bucketWebsiteDomainName,
originProtocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY
},
behaviors: [{
isDefaultBehavior: true,
compress: true
}]
},
{
customOriginSource: { domainName: `${api.restApiId}.execute-api.${this.region}.amazonaws.com/prod` },
behaviors: [
{
pathPattern: "/api/*",
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
defaultTtl: cdk.Duration.seconds(0),
forwardedValues: {
queryString: true,
headers: ["Authorization"],
},
},
],
}]
The problem was that Cloudfront prepends the path that we are using as a custom behavior with each request i.e. when we call domain.com/api/something, It will not call ${api.restApiId}.execute-api.${this.region}.amazonaws.com/prod/something. Instead it will call ${api.restApiId}.execute-api.${this.region}.amazonaws.com/prod/api/something.
Therefore, either the stage name of the default API Gateway URL which is usually prod should be equal to the behavior path which we specify i.e /path/* or /api/* or /backend/* etc -> /prod/* or we should have a /path/ as a resource at the top level of RestApi and nest all the resources under it

Related

Access to XMLHttpRequest has been blocked by CORS policy using custom domain: AWS API gateway

I have a custom domain linked to my test stage in the AWS API gateway.
I have a method as seen in the attached picture and have enabled cors (as also attached in the picture.
The endpoint will call my lambda function (with proxy lambda enabled as well)
I call the api endpoint from my Ionic angular application like so:
axios.defaults.headers.post['Content-Type'] = 'application/json';
return axios.post(url, {
data
}).then((response) => {
if (response.data.status == 'success') {
});
but in my console I get the following error:
Access to XMLHttpRequest at 'https://test.mycustomendpoint.com/auth/v1/?action=login' from origin 'http://localhost' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
I am wondering what I may be doing wrong.
Image11
Image22
This problem only happens when you run the app using serve to solve it just install this chrome extension on your device from here

What should be put in 'Access-Control-Allow-Origin' header for CF dist and route53

I have Cloud Front distribution URL (https://abcdef.cloudfront.net/) backed by Route53 (https://example.com).
I need to set 'Access-Control-Allow-Origin' header - I am not allowed to put '*' here.
So the question is whether to put the Cloud Front distribution URL or the Route53 URL.
I am not sure which one will work, or either one will work?
A bit more context:
So I have a full-stack application - The UI part is build and copied to a S3 bucket which is then linked to the above Cloudfront Distribution (https://abcdef.cloudfront.net/).
This particular Cloudfront distribution is then backed by a hosted zone DNS via Route 53 (https://example.com).
I have multiple back-end AWS Lambdas hiding behind an AWS API Gateway which has an Integration Request as Type: LAMBDA_PROXY.
The headers are part of the response of the Lambdas, as below:
'Content-Type': 'application/json',
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '1',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload',
'Access-Control-Allow-Origin': '*'
The Security scan is raising the below issue:
Risk Name
Overly Permissive CORS Access Policy
Vulnerability
Scan detected that the "Access-Control-Allow-Origin" header is too permissive.
Threat
It is possible to gather sensitive information about the web
application such as usernames, passwords, machine name and/or
sensitive file locations
It is possible to persuade a naive user to supply sensitive
information such as username, password, credit card number, social
security number etc.
Given the fact you use the LAMBDA_PROXY request type behind API Gateway, your lambda function is responsible for returning the correct headers. I suggest the following:
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type", // check API Gateway configuration which headers are allowed by default
"Access-Control-Allow-Origin": "https://www.example.com", // you add the domain which is used to make the request
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify('Hello from Lambda!'),
};
References:
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

Use AWS CDK to set up a CloudFrontWebDistribution to have GET /subdirectory server /subdirectory/index.html from an S3 bucket

I'm using the https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/static-site AWS CDK example to configure a Cloudfront + S3 bucket to serve a static site.
It does not seem like requests to GET /subdirectory responds with /subdirectory/index.html though. How would one use the CDK to configure Cloudfront + S3 to serve /subdirectory/index.html?
if you don't want to use lambda, you can redirect errors to index.html which is how you are supposed to host SPA on CloudFront using
errorConfigurations: [
{
errorCode: 403,
responseCode: 200,
responsePagePath: '/index.html',
errorCachingMinTtl: 10
}
]
for more info see https://docs.aws.amazon.com/cdk/api/latest/docs/#aws-cdk_aws-cloudfront.CfnDistribution.CustomErrorResponseProperty.html
I ended up with a solution to create a Lambda#Edge function, which performed the Url Rewrite.
https://briantakita.com/posts/static-https-websites-using-aws-cdk-cloudfront-and-s3
The source code is contained in this gist.

Getting AWS AppSync to work with CloudFront and a custom domain name

I've got an AppSync server, which uses an API_KEY generated by AppSync. Previously I had a React application in S3, and just the raw AppSync API url. That worked absolutely fine. Since putting them both behind a domain name in Route53, both backed by a separate Cloudfront distribution, I get the following error:
{
"errors" : [ {
"errorType" : "UnauthorizedException",
"message" : "You are not authorized to make this call."
} ]
}
I think the x-api-key header is possibly being stripped out between Cloudfront and the AppSync origin. But I can't see where to allow custom headers in Cloudfront. Do I also need to enable IAM roles between Cloudfront and AppSync?
UPDATE:
I found the custom-headers section, added those, they appear in the request headers now but still the same error.

API Gateway using serverless-domain-mananger returns 403 error

When I use the custom domain https://api-dev.testapp.net:
OPTIONS https://api-dev.testapp.net/dev/locations 403 ()
Failed to load https://api-dev.testapp.net/dev/locations: Response to
preflight request doesn't pass access control check: No 'Access-Control-
Allow-Origin' header is present on the requested resource. Origin
'https://xxxxx0f67xxxxxe7963c04cxxxxx23bf.vfs.cloud9.us-east-
1.amazonaws.com' is therefore not allowed access. The response had HTTP
status code 403. If an opaque response serves your needs, set the
request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have set up an API where each path is a microservice, all pointing back to a custom domain name. Each stage also has a different domain.
I am using cognito for user authentication and as far as I can tell the authentication is functioning properly.
Here is a sample of my serverless.yml
service: testapp-location
plugins:
- serverless-domain-manager
custom:
stage: ${opt:stage, self:provider.stage}
domains:
prod: api.testapp.net
test: api-test.testapp.net
dev: api-dev.testapp.net
customDomain:
basePath: "locations"
domainName: ${self:custom.domains.${self:custom.stage}}
stage: "${self:custom.stage}"
createRoute53Record: true
package:
include:
- models
provider:
name: aws
runtime: nodejs6.10
stage: ${opt:stage, 'dev'}
environment:
DATABASE_HOST: ${file(../../config/api/${self:provider.stage}.config.json):DATABASE_HOST}
DATABASE_NAME: ${file(../../config/api/${self:provider.stage}.config.json):DATABASE_NAME}
DATABASE_USERNAME: ${file(../../config/api/${self:provider.stage}.config.json):DATABASE_USERNAME}
DATABASE_PASSWORD: ${file(../../config/api/${self:provider.stage}.config.json):DATABASE_PASSWORD}
region: us-east-1
I have confirmed that the Route 53 entry has been set-up and pointing to the Cloudfront distribution.
The base path mappings are also set-up and the custom domains have valid TLS certs attached to them.
Things should be working, but I think I need a hand debugging this. Any help would be appreciated.
Edit 1: When I use the API Gateway generated url (e.g. OPTIONS https://nnxxxxxe1d.execute-api.us-east-1.amazonaws.com/dev/locations) with no addition headers the request is successful. This makes sense since there is no authorizer on this endpoint and it has a hardcoded 200 response body.
Edit 2: When I run the request (OPTIONS https://api-dev.testapp.net/dev/locations) in Postman I get the following response:
Connection →keep-alive
Content-Length →23
Content-Type →application/json
Date →Thu, 26 Jul 2018 13:40:59 GMT
Via →1.1 b790a9f06b094xxxxxxxxb87e81d4b7f.cloudfront.net (CloudFront)
X-Amz-Cf-Id →3M9kxxxxxxxxlW9Fos_lZqw-lGdPp9MCI7xFIS2-LcXpjGNolsT7jA==
X-Cache →Error from cloudfront
x-amz-apigw-id →Ko1xxxxxxxxF1LA=
x-amzn-ErrorType →ForbiddenException
x-amzn-RequestId →881153c6-90d9-11e8-8d65-738000007497
Which makes me think that the problem is with CloudFront refusing the request.
What is your Access-Control-Allow-Origin value in your request?. If you don't have it, Add the following to the header of your request:
Access-Control-Allow-Origin: *
I'm suspicious that, because your request goes through multiple access points, the token is not being passed by. Also add domain=whateverdomain.com when you attach the cookie for the authorized user.
I had the same problem. The difference in my environment is that I've an extra cloudfront distribution fronting the API gateway (for TLS version enforcement purposes).
I received the same errors:
Error: 403 - Forbidden
X-Cache → Error from cloudfront
X-amzn-ErrorType → ForbiddenException
Turns out the API gateway had a custom WAF which didn't have any rules and was denying everything. The fact that I have multiple cloudfront distributions and that the WAF is "hidden" under a regional filter made detection of this quite hard.