Question

In OAuth2.0 we have to send client id and secret along side the user credential to obtain an access token from an authorization server. We have a ReactJS web application that needs to send its request to API gateway (Main API), but problem arise when the web application wants to store the client secret for its requests: React JS and API gateway

In this scenario I am totally aware that storing the secret on web app would expose the secret to the WILD internet and everyone can create a new application from ground up and sends it request to API gateway.

What I came up with is to create a middleware gateway on server that would store the secret and its whole functionality would be to get an access token from API gateway by its secret and the client id which is given by ReactJS web application. enter image description here The whole responsibility of Secret Holder is that it just keep the secret for the web application and obtain an access token for the ReactJS app.

I've gone through all the questions below but could not satisfy myself to design an extra module for just serving access token for the web:

In the future we would definitely have iOS & Android applications too.

How do you guys handle your client id & secret in your web applications? Is the 2nd scenario good enough or is there a best practice that I'm unaware of?

I would appreciate if anyone could shed some light on this question.

Was it helpful?

Solution

Your tl;dr version is "of course not", but the underlying issue here is a fundamental and very common misunderstadning of what secret really means in these contexts.

First things first, there is absolutely no way you can guarantee that a secret will remain ... well ... secret when distributed to client apps; that's regardless of whether they are web based or otherwise (mobile or IOT for example).

In fact, using AWS Cognito as an example, they even explicitly mention the above in their docs on client apps and secrets:

If a secret is created for the app, the secret must be provided to use the app. Browser-based applications written in JavaScript may not need an app with a secret.

And for good reason – what good is a secret in a browser app where anyone can right-click their way to it in a few seconds?

And even for clients distributed in a "packaged" fashion with no direct access to the source code like mobile apps, secrets can still be recovered; all you can do is obfuscate them and hope no-one is going to decide they really need to find them. They are merely an inconvenience to whoever might be attempting to do something fishy.

Actual secret comms can be enabled with flows involving a "server in between" but it comes down to the specifics of your situation. For example, borrowing from Cognito again:

For security reasons, we highly recommend that you use only the Authorization code grant flow, together with PKCE, for mobile apps.

They key thing to remember is if it leaves the app / is part of a request it is not a secret, and even if it doesn't it is still possible that it gets compromised.

Keep in mind that all the above hold true for client secrets / API keys when involving unauthenticated calls (e.g. sign up calls or API calls to get a products list on an e-commerce platform) only. Authenticated calls are a different thing and would require some sort of MITM attack or physical access to the attacked account to get ahold of.

Summing up:

  1. Client secrets and API keys distributed to client apps are simply outside of your control to keep secret by definition and as such should at any given moment be considered as good as compromised.

  2. Knowing the above, and assuming you want to "keep people off your back" you can include a rotation strategy for publicly distributed secrets to make it harder / inconvenient for people to get to them and (depending on how much effort you wish to spend on it) potentially identify them.

  3. You should still use them for mobile apps in combination with PKCE, just obfuscate them to the best of your ability first to minimize the potential of exposure (if and only if you're using them to calculate something like a HMAC locally or using some other way to protect them like SSL pinning) but keep in mind that even then people will still figure out ways to uncover them.

OTHER TIPS

Just have your client id and secret change in each request for the app, make it expire early, and maybe link it to a refresh token too. If you want to prevent a client from accessing, revoke the refresh token. Store your dynamic client secret in secure cookie and ensure https.

Licensed under: CC-BY-SA with attribution
scroll top