14

When I deployed a React Router app to AWS S3 and CloudFront and when I try to access React routes directly it gives the following error with 403 error code. I can access both the base URL(www.sample-app.com) and route URLs(www.sample-app.com/cart) when it flows through the app.

But If I try going directly to a React route(www.sample-app.com/cart) it produces a 403 Access Denied error as follows. The major pain point is it produces this error when I try to refresh a React route URL.

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>REQUEST_ID</RequestId>   
  <HostId>HOST_ID</HostId>
</Error>

Note: I'm using AWS load balancer and Lambda functions as backend. I have setup AWS ALB and Cloudfront to authenticate users with AWS Cognito.

Appreciate your help on this.

Chamin Wickramarathna
  • 1,672
  • 2
  • 20
  • 34
  • This is because static file servers rely on the requested file actually existing. Since there is no server-side code to handle the route when you directly try a URL, it fails. Using hash history created by a an option for you? – Sanish Joseph Jan 29 '21 at 05:15

4 Answers4

10

Because cloudfront can only access files that do exist in the bucket, and if a nonexisting object is request it will return 403, you need to add a custom error page, that returns the index.html file with a 200 status code. Then, because the index.html was returned, the React Router can do its job.

More info here:

https://www.codebyamir.com/blog/fixing-403-access-denied-errors-when-hosting-react-router-app-in-aws-s3-and-cloudfront

aleochoam
  • 159
  • 1
  • 5
  • I get this approach, however I built a react app through nextjs and it's still throwing 403 errors on my html pages in the bucket, and when I do this it loads the home page with the current page path whenever I refresh the page – roninMo Apr 18 '22 at 16:36
9

Easiest option, hands down, is to create a simple custom error in the your CloudFront instances "Error pages" tab. See the attached image. It's a 30 second fix and works as soon as it auto-deploys.

CloudFront - Error pages tab.  Create custom error response.

Mark Hall
  • 475
  • 1
  • 8
  • 14
  • This is a great article that explains another little trick to help fixing the problem. https://medium.com/@xergiodf/react-router-404s-pages-nginx-apache-amazon-s3-93f9b55e21f3 – DPalharini Jun 14 '23 at 15:00
4

When using CloudFormation to create Cloudfront Distribution, use the following in the DistributionConfig Section

"DistributionConfig": {
//Other configs
 "CustomErrorResponses":[
     {
         "ErrorCachingMinTTL" : 1,
         "ErrorCode" : 403,
         "ResponseCode" : 200,
         "ResponsePagePath" : "/index.html"
       }
  ]
}
zeddarn
  • 302
  • 2
  • 14
  • Thank you for this snippet! Obviously if you're using Cloudformation this is the ideal way to handle this issue. – Nick Cappello Nov 08 '22 at 20:54
  • This should be the correct answer. The configuration can be done using the same fields from the interface if you need, just click on your distribution > Error Pages and create the custom response. Don't forget to invalidate the cache to propagate the changes to the CDN. – Lazaro Fernandes Lima Suleiman Nov 18 '22 at 23:58
0

Like I mentioned in the comment, you can't use <BrowserHistory> when you host in a static site. You need a mechanism to redirect all URLs to your index.html so react-router will take over.

To Achieve this you will need some server-side code and hosting for the same. S3 won't work as it can handle only static files. If S3 is the only option, use or there is a hack mentioned [here][1]. I won't recommend it but there is one.

If you are planning to use server-side code here is an example of how NodeJs Express can be used to get the routing work,

app.use(express.static(path.join(__dirname, 'dist')));
app.get('*', function(req, res) {
    res.sendfile('./dist/index.html');
});

assuming your build is in the dist folder. [1]: react router doesn't work in aws s3 bucket

Sanish Joseph
  • 2,140
  • 3
  • 15
  • 28