Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OAuth flow for third party API access

There is a lot of information on the web about OAuth 2, its different types of flows and where/how to use them. I find that most of these resources discuss authenticating a user for an application, but I am struggling to understand what the best/correct approach would be when consuming third party APIs (i.e. when our own API is the "middleman" between a user and their data in a third party API).

With the help of an example scenario and some diagrams, I would be really grateful for advice/opinions on how I should properly implement integration with third party APIs and what the pros & cons of each approach are.

Starting point

As a starting point, suppose we have a web app, structured as follows:

  • Frontend - SPA (Angular), hosted with AWS S3 + Cloudfront
  • Backend - Node, running as stateless AWS lambda functions with AWS API Gateway
  • Auth0 for handling auth/signin etc. The frontend uses an Implicit OAuth2 flow to obtain access_tokens, which are stored in local storage and included as a header in all requests to the backend.
  • Potentially also native mobile app(s), consuming the same backend API.

Goal

Now suppose that we wish to add integration with Google Sheets. The new feature would allow users to use their own Google Sheets (i.e. stored in their own Google account) as a data source, with the app having read&write access to the sheet. There may be other integrations in the future, so I am assuming that other APIs would require a similar process.

Problem statement

In addition to the existing OAuth process (which allows users to sign in to the "MyApp" frontend and communicate with the "MyApp API"), there needs to be an additional OAuth process for users to connect MyApp to the third party Google Sheets API.

The documentation has two Quickstart examples, but neither seems to quite fit my needs: Browser - https://developers.google.com/sheets/api/quickstart/js Node.js (console app) - https://developers.google.com/sheets/api/quickstart/nodejs

The data from the third-party (Google) API is one of potentially several integration points, so intuitively it seems more logical (and more secure) that all communication with the Google Sheets API should happen in the MyApp API, and not on the frontend/client side. The MyApp API would fetch data, process/manipulate/format it in some way and then present it for display in the frontend or mobile apps.

We require access to each user's own data, so the Client Credentials flow is not suitable. I am focussing on the Implicit or Authorization Grant workflows.

Important note: The trickiness seems to come from the fact that the MyApp API is stateless, so there is no long-lived session in which to store tokens. On that basis, it seems like tokens need to be stored either in the frontend (e.g. local storage/cookies etc) or in a backend database.

Below is my interpretation of two possible approaches. I'd appreciate thoughts/corrections.

Option 1: Implicit flow - tokens stored FE, passed along to BE which then makes requests to Google

Option 1

Pros:

  • Allows access to user's own data
  • Simpler flow, access_token retrieved immediately without needing the code step
  • Less steps to implement between initial sign-in process and actually obtaining data
  • No need for a backend database, can resend the token with each request

Cons:

  • Frontend (browser) has access to Google access_token which seems unnecessary and is a potential security concern
  • It seems like a strange process to pass the access_token from FE to BE, purely to allow BE to then use that token to make another request
  • I'm not sure how we would refresh/renew tokens since I understand that storing refresh_tokens on the client is bad practice. It would not be a good user experience if the user had to frequently sign in to reconnect their account

Option 2: Authorization Code Flow - all communication with Google via BE, tokens stored in BE database

Option 2

Pros:

  • Allows access to user's own data
  • Other than the code-request / consent page, all communication with Google is implemented backend, so the tokens are not accessible on the client
  • Client secret can be used from the BE

Cons:

  • More complex flow, requires extra steps
  • Given that the BE is stateless, it's not clear how best to store the tokens. It seems like it would require storing them in a database which is extra complication and seems like it would have security implications - how would you properly secure / encrypt the access_token/refresh_tokens in said database?

Conclusion

Given that the data processing is to happen on the backend, option 2 seems slightly more suitable because the sensitive tokens can be hidden from the frontend app, and several clients (web frontend, mobile apps) have less obligation to be involved in the process with the exception of the initial sign in / user consent. However I’m not sure whether having a database full of user auth tokens is a good idea or how I could properly protect this database.

like image 542
Matt Wilson Avatar asked Oct 15 '22 14:10

Matt Wilson


1 Answers

The good news is that both options are perfectly valid and equally secure. The concern about a short-lived Access Token being in the browser isn't an issue. Equally, if you only held the tokens on the BE, then you would need to implement your own client authentiation/session/JWT blah blah, which presents the same attack surface.

I've done both, and am currently migrating from BE to FE. In my case the reason is that everything I need to do, I can do on the FE, so I end up with no BE at all. This isn't strictly true since I do some onboarding/payment with the BE, but that's about all.

So the best approach depends on factors beyond those in your question, such as the nature of app, what the BE cost is and how important that is, what your devops skillsets look like for maintaining two environments, to what extent a BE is required anyway, vs being completely optional.

like image 125
pinoyyid Avatar answered Oct 21 '22 05:10

pinoyyid