# Security question re SPA and Api Gateway

**URL:** <https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396>\
**Category:** Serverless Architectures\
**Tags:** aws\
**Created:** [December 28, 2017, 10:03pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396 "2017-12-28T22:03:57Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [December 28, 2017, 10:03pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/1 "2017-12-28T22:03:57Z")

</div>

I want to develop a react.js single page app with a serverless backend similar to the serverless stack arch( [serverless-stack.com](http://serverless-stack.com) i.e. no middleware server in the middle).

Users of the app will initially authenticate from another website which will then forward them with oauth data to a callback url i.e. a path in my react app with some oauth data including user info and a token.

At this stage I will want my react app to make a api gateway call to create or update this user/token info in my aws database e.g. createOrUpdateUser(userinfo, token).  
The data in the database I would assume would then be used by a custom authorizor to validate each subsequent api gateway call which would be passed the token

My question though is this: How do I guard the createOrUpdateUser() api to stop it being maliciously getting called by anyone other than the react app ?

---

<div class="post-metadata">

**Author:** ![buggy](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/buggy/32/177_2.png) [@buggy](https://forum.serverless.com/u/buggy)\
**Post date:** [December 29, 2017, 7:33am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/2 "2017-12-29T07:33:26Z")

</div>

> [@walshe](#):
>
> My question though is this: How do I guard the createOrUpdateUser() api to stop it being maliciously getting called by anyone other than the react app ?

If you can use Amplify or Auth0 then your life will be a lot easier.

I think you’ve simplified OAuth too much. Part of the process involves validating the temporary token you receive in the callback while you exchange it for a one you can use with API calls. During this step you can issue your own session token to the React app. The API to exchange the token doesn’t really need protecting. There are a bunch of checks you need to do before calling the OAuth provider and the OAuth provider will return a failure if the code is wrong.

---

<div class="post-metadata">

**Author:** ![bill](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/bill/32/1072_2.png) [@bill](https://forum.serverless.com/u/bill)\
**Post date:** [December 30, 2017, 12:38am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/3 "2017-12-30T00:38:56Z")

</div>

> [@buggy](#):
>
> Amplify

What’s the product, do you have its website for reference?

---

<div class="post-metadata">

**Author:** ![buggy](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/buggy/32/177_2.png) [@buggy](https://forum.serverless.com/u/buggy)\
**Post date:** [December 30, 2017, 12:47am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/4 "2017-12-30T00:47:36Z")

</div>

@bill It’s an open source project from AWS that integrates a number of existing products - Cognito, Pinpoint, S3, etc - so that they’re easy to use in a serverless environment.

> **[GitHub - aws-amplify/amplify-js: A declarative JavaScript library for...](https://github.com/aws-amplify/amplify-js)**
>
> A declarative JavaScript library for application development using cloud services. - GitHub - aws-amplify/amplify-js: A declarative JavaScript library for application development using cloud services.

[![](https://img.youtube.com/vi/vAjf3lyjf8c/hqdefault.jpg "AWS re:Invent 2017: Analytics, Authentication and Data with JavaScript: AWS Amplify (MBL403)") ](https://www.youtube.com/watch?v=vAjf3lyjf8c)

[![](https://img.youtube.com/vi/VoRFXHHzHMw/maxresdefault.jpg "Adrian Hall: AWS Amplify (Javascript) & AppSync (GraphQL)") ](https://www.youtube.com/watch?v=VoRFXHHzHMw)

---

<div class="post-metadata">

**Author:** ![bill](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/bill/32/1072_2.png) [@bill](https://forum.serverless.com/u/bill)\
**Post date:** [December 30, 2017, 12:48am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/5 "2017-12-30T00:48:26Z")

</div>

Thanks a lot, @buggy

---

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [December 30, 2017, 5:22pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/6 "2017-12-30T17:22:53Z")

</div>

yeah I think I had it wrong a bit. Actually I cannot use Auth0 in this case I think. Basically a site called BigCommerce authenticates the user and then forwards them to my app via a callback url with a oauth token… so I think this is how it shoudl basically work now…

1. User authenticates with BigCommerce
2. Success auth forwards user to a calback url (my single page app) with oauth token. Single page app stores the oauth token in browser storage
3. Now each time SPA needs to invoke a api gateway it will supply the oauth token in the headers. A configured lambda custom authorizer will intercept the request and verify the oauth token and then return an IAM deny or allow policy which will dictate whether the api gateway can be proceed to be invoked or not.

Some where along the way I will need to store user info from the oauth token in my own database. I guess I could do some sort of createUserIfNotExists() logic in my authorizer. It does sound like a lot of logic to have to execute each time in an authorizer but if I use the time to live caching feature then it may not be so bad ?

---

<div class="post-metadata">

**Author:** ![jonsmirl](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/jonsmirl/32/776_2.png) [@jonsmirl](https://forum.serverless.com/u/jonsmirl)\
**Post date:** [December 30, 2017, 6:49pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/7 "2017-12-30T18:49:44Z")

</div>

There is AssumeRoleWithWebIdentity  
[https://docs.aws.amazon.com/STS/latest/APIReference/API\_AssumeRoleWithWebIdentity.html](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html)  
This requires a supported identity provider. Maybe your site is implementing OIDC? It so, you can set it up in IAM as an Identity provider.

There are also Developer Authenticated Identities  
[https://docs.aws.amazon.com/cognito/latest/developerguide/developer-authenticated-identities.html](https://docs.aws.amazon.com/cognito/latest/developerguide/developer-authenticated-identities.html)  
With developer authenticated identities you can store the tokens in a Cognito Identity Pool.

---

<div class="post-metadata">

**Author:** ![DavidWells](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/davidwells/32/201_2.png) [@DavidWells](https://forum.serverless.com/u/DavidWells)\
**Post date:** [December 30, 2017, 8:19pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/8 "2017-12-30T20:19:42Z")

</div>

This is a fully working react + serverless app with auth0 for auth

> **[GitHub - serverless/forms-service: Serverless Forms Service to collect form...](https://github.com/serverless/forms-service)**
>
> Serverless Forms Service to collect form data with Admin UI - GitHub - serverless/forms-service: Serverless Forms Service to collect form data with Admin UI

I gave a talk on it recently (no video yet) here are the slides with further explanation of the setup [http://bit.ly/sls-auth-slides](http://bit.ly/sls-auth-slides)

---

<div class="post-metadata">

**Author:** ![buggy](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/buggy/32/177_2.png) [@buggy](https://forum.serverless.com/u/buggy)\
**Post date:** [December 31, 2017, 4:45am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/9 "2017-12-31T04:45:08Z")

</div>

@walshe I’ve done something similar with Shopify and it required building two API to start and complete the auth process in order meet all of the validation requirements and keep my Shopify API secret from users. I see BigCommerce now uses OAuth 2.0 so I imagine their process is similar. I would strongly suggest that you start with pen & paper then draw the authentication process on paper along with what information flows in each direction and what information you need to keep secret. Once you’ve done that I think you’ll have a very different view of how it works.

---

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [January 2, 2018, 3:39pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/10 "2018-01-02T15:39:29Z")

</div>

thanks for link @DavidWells

---

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [January 2, 2018, 3:41pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/11 "2018-01-02T15:41:13Z")

</div>

thanks @buggy I’ll have a look…

authentication always such a bugbear of mine ☹

---

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [January 20, 2018, 4:22am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/12 "2018-01-20T04:22:22Z")

</div>

BigCommerce doesn’t support OIDC

---

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [April 2, 2018, 6:30pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/13 "2018-04-02T18:30:24Z")

</div>

@buggy just one more on this…

In my oauth callback (the lambda), and after I do all the handshake process with the external provider I need to redirect to my react app obviously.

Since we cant use a session in a serverless architecture, I am therefore creating a customjwt token and passing it to the react app as a query param over https in the redirect 302.

```
callback(null, {
          statusCode: 302,
          headers: {
              Location: `${process.env.HTTPS_APP_URL}?token=${token}`
          }
      }) ;

```

All subsequent requests to my other apig/lambdas use the jwt in the header and are checked by a custom authorizer where the jwt in the header is verified.

My question is if the passing of the token in the redirect is safe ? whats a better way?

---

<div class="post-metadata">

**Author:** ![buggy](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/buggy/32/177_2.png) [@buggy](https://forum.serverless.com/u/buggy)\
**Post date:** [April 4, 2018, 3:47am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/14 "2018-04-04T03:47:36Z")

</div>

Currently my callback page is in the SPA. After loading it calls my API using POST to get an access token. This avoids needing to pass tokens as query string parameters which I don’t like doing because the token is publicly displayed and potentially it appears in cache logs.

Lately I’ve been looking at Cognito, Amplify and AppSync so my approach might change in the next few days as I get more serious about that combination.

---

<div class="post-metadata">

**Author:** ![walshe](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/walshe/32/1032_2.png) [@walshe](https://forum.serverless.com/u/walshe)\
**Post date:** [April 4, 2018, 1:31pm UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/15 "2018-04-04T13:31:27Z")

</div>

ah - so you are saying you get the external auth provider to callback to the SPA rather than a serverless apig, and from **there** you do a post to your apig where the handshake is completed and then you just return the token back in the post response ? @buggy

---

<div class="post-metadata">

**Author:** ![buggy](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.serverless.com/buggy/32/177_2.png) [@buggy](https://forum.serverless.com/u/buggy)\
**Post date:** [April 6, 2018, 10:37am UTC](https://forum.serverless.com/t/security-question-re-spa-and-api-gateway/3396/16 "2018-04-06T10:37:22Z")

</div>

@walshe Correct. My complete process is this

/login is part of the SPA. It makes an API call that returns a JWT token which is stored in the browser and a redirect URL that the user is sent to.

/callback is part of the SPA. It passes the query string parameters plus the JWT token from the first step to another API which handles the authentication and returns a session token generated by the API to authenticate future API calls (a different JWT).

This approach uses the JWT token like a session storage during the OAuth process and means the browser doesn’t get access to anything it wouldn’t have access to during the regular OAuth flow.
