0

I have configured cognito based authentication and everything is working on my local machine, however when I push the compiled nuxt application to S3, I get the following error after login:

<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>YJ5VBAF69BFHNTRA</RequestId>
<HostId>+ROpBRvEbtrVxTgwqSfhDvK5jwhCfbD9eoE3X6RslkFghQXDL+NwkupIqXoYW2Em9ZoBEhP31Oo=</HostId>
</Error>

This seems to be an s3 error, and I am not sure what is causing it as the site acts like normal otherwise.

Can be repeated by registering and trying to login to the site (copyswapper.com).

June Lewis
  • 355
  • 1
  • 6
  • 28
  • Some javascript on that page is changing the browser's URL to "/login" after loading the page. Even just hitting refresh on the main page after it loads is enough to trigger that error, seeming because you don't have an object in S3 named "login". – Anon Coward Mar 07 '22 at 00:18
  • There is a file at /login/index.html – June Lewis Mar 07 '22 at 01:21
  • @JoelLewis https://stackoverflow.com/a/69157535/17896613 Use the CloudFront function based answer from here. It is faster than the old Lambda@Edge solution. – Kaustubh Khavnekar Mar 13 '22 at 06:13
  • Note: Based on the website response headers OP is using CloudFront. – Kaustubh Khavnekar Mar 13 '22 at 06:14

1 Answers1

2

This is a problem serving the default document (index.html) - instructions on fixing it below.

LOCAL DEVELOPMENT

On your local machine, a development web server, eg the webpack one, serves index.html regardless of the path the user browses to within the vue.js app:

  • http://localhost:3000/login

AWS

I see you are deploying static files to S3, then serving them via Cloudfront. But the default document handling works differently, meaning this path does not serve an index.html file, and results in an error instead:

AWS PERMISSIONS

I have a demo Single Page App hosted the same way, which you can run from this page to compare against. The standard setup is to only allow Cloudfront to access files, via permissions like this. It results in the above errors if a file is missing though:

{
    "Version": "2008-10-17",
    "Id": "PolicyForPublicWebsiteContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity H1D9C6K7CY211F"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::web.authsamples.com/*"
        }
    ]
}

CONCERN 1: DEFAULT DOCUMENT HANDLING

You need to provide a lambda edge function to serve the default document, regardless of the path of the user within your Single Page App:

Here are a couple of paths for my demo SPA. Note that the first of these could be a path within the app, so the default document handling deals with that. The second of these results in a non-existent Javascript file, and I did not try to fix that, so it results in the same error you are getting:

CONCERN 2: SECURITY HEADERS

While you are there you should also write a lambda edge function to use recommended security headers, similar to this:

If you then browse to Mozilla Observatory and type in your site name, you will get a better security rating, as for my demo app:

LAMBDA EDGE TESTING AND DEPLOYMENT

The lambda edge functions can be managed in a small subproject, as in my example. I use the Serverless framework, meaning the logic is expressed in a Serverless.yml file and I then run these commands during development, to test the logic:

npm install
npm run defaultDocument
npm run securityHeaders

I then deploy the code with these commands:

npm run package
npm run deploy

SUMMARY

Single Page Apps are not 100% static, and require some code to handle the two concerns mentioned above.

Gary Archer
  • 22,534
  • 2
  • 12
  • 24
  • 1
    You can use CloudFront [Response Headers Policies](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-response-headers.html) to set the security headers instead of writing a function for it. For the index.html rewrite, the newer CloudFront functions might be more suitable than Lambda@Edge since there is no complex computation. AWS has an example in its [samples repo](https://github.com/aws-samples/amazon-cloudfront-functions/tree/main/url-rewrite-single-page-apps) which you can combine with your code. – Kaustubh Khavnekar Mar 17 '22 at 19:21
  • That's nice - will make a note and take a closer look some time soon - thanks for that. – Gary Archer Mar 17 '22 at 19:29