-1

I want visitors of my website to be able to provide their email address in a form to get future company updates. Once they submit the form an email would be sent to their address with a link to click on, say www.mywebsite.com/<token>. Upon visiting that link their email would be validated and become part of the database I would use to send updates.

I have in mind deploying my website using AWS S3 together with AWS CloudFront and AWS Certificate Manager. For the implementation of the email verification process: a Lambda function would be triggered through API Gateway when a user submits the form, the token would be generated in that function, and an email would be sent to the visitor with a call to AWS SES.

I'm having issue understanding within that framework how I can create dynamically and serve URLs of the form www.mywebsite.com/<token>. I can see that with a server up and running in the backend, this could be achieved with something along the lines of

const express = require('express')
const app = express()

app.get('/verify-email/:token', async (req, res) => {
  const token = req.params.token;
  // check token
  // if match, validate email, add to database, and render page
  // if no match, redirect
});

How can I create and serve these URLs within the S3 framework I detailed above?

Do I need otherwise to change the implementation and run instead an EC2 server or use another AWS service?

  • 1
    This is a stateless design. Cognito is not a good fit. This is not really a user authentication/management issue but a simple token handling problem such as SSO or any other token uses. – cyberwombat Aug 10 '23 at 13:20

1 Answers1

1

You're on the right track. API Gateway/Lambda is perfect for this. It's not clear what you mean by "How can I create and serve these URLs within the S3 framework I detailed above?" since you mentioned creating these in the gateway but I assume you refer to what happens once the user clicks the link in their email.

You can either create a GET route in the API gateway - this route will need to be publicly accessible (no auth). The Lambda can verify token (use JWT tokens for this as they are made for just this) and then send a redirect to say a thank you page on your S3 site.

Alternatively you can have the S3 site handle that token route, then have it make a call to the server to process and return a success/fail. This would work well for example with a React site.

In order to handle the <token> route on front end you would either use some of the built-in utilities your framework would have (for example if you used NextJS then useParams()) or use JS/JQuery to parse the path. You will only have a single page - i.e. index.html - that will handle all of this. This is defined in your S3 config. Meaning no matter what URL you type (domain.com, domain.com/sometoken , domain.com/contact, etc) the index.html will render and it's up to JS (native, JQuery, React) to parse the path and determine what to do next. If you intend to have other pages such as contact then Id recommend using something like /auth/<token> in order to help differentiate token URLS from the other pages.

On a side note, you can have a single Lambda on API gateway run an Express app using some libs such as this for NodeJS.

On an additional side note, Lambdas have Function URLs which can be useful - they do not provide auth/throttling etc that the gateway does nor can you change the domain/URL but would work well for the 2nd scenario.

cyberwombat
  • 38,105
  • 35
  • 175
  • 251
  • (1/3) Thanks for the links and advice, that's very helpful. The wording I use was probably not the correct terminology. With the S3/CloudFront approach I understand I need to populate the bucket with `.html`, `.css` and `.js` files to render my website. I fail to see though where the files for the URLs `www.mywebsite.com/` would have lived since every `token` would be dynamically generated and unknown beforehand. That's the issue I had: how to have those files in an S3 bucket for the URLs `www.mywebsite.com/` to be eventually rendered when the tokens do not exist yet. – KeyboardOnFire Aug 10 '23 at 14:34
  • (2/3) The idea of using API Gateway came from that [AWS architecture blog](https://aws.amazon.com/blogs/architecture/create-dynamic-contact-forms-for-s3-static-websites-using-aws-lambda-amazon-api-gateway-and-amazon-ses/) and was addressing the process of "the-user-submits-their-email-through-the-form", not "the-user-visits-the-token-URL-just-generated". I understand from your answer the API Gateway can handle that token route itself, thanks for this - I'll dig further into this option to check how it can be implemented. – KeyboardOnFire Aug 10 '23 at 14:34
  • (3/3) *Re one single lambda on API Gateway with an Express app.* For the use case I have, is that effectively equivalent to having an EC2 instance running a server (mentioning this as it's my only point of reference so far) but with all the benefits highlighted in "Why run Express in a Serverless environment" in the link you shared? Sounds that would be the best option to explore. – KeyboardOnFire Aug 10 '23 at 14:35
  • @KeyboardOnFire Ah I see. I updated answer with notes on this. – cyberwombat Aug 10 '23 at 14:40
  • As far as EC2/Lambda - the end result will be the same but you'll be paying a few bucks for EC2 - especially since now you have to pay for the public IP. Lambda will usually be much cheaper for this since it will only run when someone submits. In conjunction with DynamoDB or Aurora Serveless this will be a pure on-demand service. – cyberwombat Aug 10 '23 at 14:42
  • Thanks for all the additional information, really appreciate it. – KeyboardOnFire Aug 11 '23 at 09:19
  • Hi @cyberwombat, I'm trying to understand how to implement the options you shared, can you help me further? (1) *Re parsing `token` in front-end.* (a) I've tried with creating a JS script within `index.html` that looks at `window.location.href` to perform redirects. This script fires only when `index.html` is served, so in the case the client visits say `www.mywebsite.com/test` the rule in this JS file doesn't fire and no redirection happens. (b) I've looked at setting up redirections through S3, here a JSON file needs to be used. Can you let me know how to implement the method you describe? – KeyboardOnFire Aug 11 '23 at 13:58
  • (2) *Re single lambda on API with Express app.* Would the architecture be: client -> API Gateway -> Lambda, and all the files (say html, or js, or ejs, ...) live in that Lambda? Or do you include CloudFront in there, so client -> CloudFront -> API Gateway -> Lambda? – KeyboardOnFire Aug 11 '23 at 14:00
  • I am referring to using Express as an api server and not to serve images/css - though you could. Your assets would reside on S3. But Id recommend exploring a separate client/server - something like React on frontend and pure API on backend to receive tokens and do DB stuff. You can use Express or Fastify and wrap all that in a lambda handler or take the dive into creating individual lambdas directly. The wrapper is really meant to help transition existing monolithic stuff to gateway. Once you separate things where you do the redirect will be clearer. – cyberwombat Aug 13 '23 at 03:34
  • 1
    This comment I write in answer to yours keeps getting deleted, that's just annoying. Thanks cyberwombat for your help – KeyboardOnFire Aug 15 '23 at 14:34