React / Axios to consume REST API with client certificate authentication - reactjs

I understand that React app is only client side application running in the client browser.
However I have the backend with REST API I need to consume, and the API in under mutual TLS (https), so I need client certificate in order to be able to authenticate and get something from the backend.
But the issue is that the React Front End is running locally in the browser so I do not know how it could be possible to securely store certificate and its private key, if it is even possible.
I was trying to google approach and it seems that the React app cannot consume services which require client certificate for authentication, and there should be at least another backend as proxy, which will be handling both parts, with the React client, and the REST API backend. This proxy can be configured with the certificate and private key and user would not have access to it.
But it requires another component as proxy.
I can also put the React app behind proxy like Apache and setup the mutual client certificate based authentication, however this can help me to identify user inside the React app, not to securely establish mutually authenticated channel with the REST API backend.
It seems that WebAuthN could be the way, however it seems to be designed only for authentication, not the SSL/TLS.
What should be the correct approach? Is it possible to do it with React based app, or this technology is not suitable in that case?

I did research on the same topic, the only solution that I found is to store the certificate on the api and request the certificate using AXIOS.
On the api level you need to test from where the request is coming from and only serve the certificate if the request comes from an authorized IP (your front end).
I couldn't find any other solution.

Related

Encrypt Django Rest Framework API response + Decrypt response in react app

I am currently building an application.
My front end is developed using React and Axios (for API call requests). It is served directly by vercel on mydomain.com
My back end is developed using Django and Django Rest. It is served with apache2 on api.mydomain.com. It only serves API endpoints.
So the front-end and back-end are separated.
I would like to return the entire data in encrypted form as an API response and then wants to decrypt it in the frontend app(react)
Do you have any idea of what I could do to achieve this?
Thanks a lot in advance for your answers.
Thats such an interesting question.
If you want encryption, I think you should look into SSL encryption (using https instead of http). SSL encrypts the data between client and server. You would still need to make API endpoints inaccessible to unauthorised users.
There is a great article about securing Django API by using JWT tokens.
You can set up a login endoint that would retrieve the tokens from Django upon successful login.
These tokens can then be used by React to access the secure Django endpoints. As an additional layer of security, you could make these tokens short lived, in the unlikely case someone intercepts the tokens, they will expire and the hacker will lose access to your API.
SSL + JWT tokens should address your needs :)

Why can't web application type 'Android' be a confidential client?

Using authorization flow and passing the information to the back-channel for the token request we don't need to save the secret in the app.
Why then does Azure force us to use a public type?
Cannot choose for the app to be a 'web' type as the redirectUri is not allowed to be anything other than 'https://foo' which in our case is 'app://auth'
edit: More information
When adding a platform on Azure AD you currently have the option between
web
spa
ios/macOS
android
mobile and desktop application
All of these are public clients except 'web' which can be confidential as the back-end is able to securely store the secret. My question is why is there a difference between web and for example an android application? The android app will communicate the exact same way a front-end application would. But choosing the android app is the only way I can configure the redirectURL for my application
An SPA being public is understandable, but forcing every mobile app to be public is something I do not understand
MOBILE FLOW
This has some differences to a web client. You are meant to use Authorization Code Flow (PKCE) without a client secret, and sign in via a Chrome Custom Tab. See this Curity tutorial for how that looks. Avoid using a web flow for a mobile client though.
MOBILE CLIENT SECRETS
Routing requests via an API that attaches a client secret is not considered standard since an attacker with your client ID and redirect URI could still trigger a flow on app:/auth.
If mobile client secrets are needed then the recommendation is to ensure a different client secret per device. This can be done using Mobile DCR. I don't think Azure supports this however.
HTTPS REDIRECT URIs
In case you're not aware, Android App Links are needed in order for mobile apps to receive authorization responses on HTTPS redirect URIs. I'm pretty sure Azure will support this, and it is a best practice since an attacker cannot get the response. More about this in a blog post of mine.
An "OAuth client" is the application which talks to the Authorization Server. In your case, you don't have a mobile client, as it's in fact the backend which talks to the authorization server. A mobile client should never be configured as confidential. Azure can't assume that all developers will be as thoughtful as you and don't hard-code the secret in their apps.
As #Gary Archer pointed out you should configure your client as a web confidential client and use HTTPS redirect uris as an Android App Link to go back to your app.
Using authorization flow and passing the information to the back-channel for the token request we don't need to save the secret in the app.
It sounds like you relate to a newer Client-Initiated Backchannel Authentication Flow. Azure does probably not support this flow, yet.
Why then does Azure force us to use a public type?
The confidential client and public client terms stems from OAuth 2.
A confidential client is an application that is able to protect its client secret. E.g. a backend application in e.g. Java, Node.js or similar.
A public client is an application that is not able to protect a secret - or where many unique instances exists. E.g. JavaScript Single Page Applications or Mobile applications - this is places where a Secret could be extracted in any client. It is now common to use a Proof Key for Public Exchange when using a Public Client.
Also see What's the difference between Confidential and Public clients? - OAuth in Five Minutes.

OAuth client secrets in React apps

I have been trying to learn about OAuth2 and OpenID Connect and this article was the most helpful so far:
https://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc
But it made me wonder:
If the "client secret" is supposed to be a secret (duh) between the Client and the Authorization Server, and the Resourse Owner is never supposed to know about it... how does this work in things like React, where the Client is run directly in the "client-side" (redundant terminology...).
I am guessing that you are not supposed to distribute your "client secret" publicly, so you clearly cannot deliver it along with your app.
A React SPA is a 'public client' and does not have a client secret, since, as you indicate, it cannot. be stored securely in a browser.
For React you would use Authorization Code Flow + PKCE to sign users in. This involves use of a secret that is generated at runtime - as well as an end user providing credentials.
It is also possible (and recommended in 2021) to proxy OAuth requests that involve tokens via a Back End for Front End API.
This allows the API to attach a client secret and in effect this upgrades the SPA to a 'confidential client'.
FURTHER INFO
I think more libraries will become available that implement this type of security in 2021. See also this video.

Securing an API from other web apps

I have a react web application with a flask api (I used to use express). The product of this app is the data that it displays. I don't want other people to be able to take that data easily from calling the api.
I want to secure the api such that it can only be accessed by my react app and nothing else. How can I do that?
The only way to truly secure your API is by authenticating your app's user with something like Oauth2 and verify that credential on server-side with something like passport, and make the authorization expire with sessions. AND use SSL so none of that is easily visible through a protocol analyzer.
Sure, you can hard-code some sort of "secret key" with the app, but anyone who want it bad enough will read it off your app or sniff the packets through a packet logger until they find the key.
EDIT: Oh, and as a part of the authorization upon login, provide them with a uniquely generated "API-KEY" as part of identity, so you can validate them upon submission, and if they violate your trust, mark their API key invalid in the server so they can't use them any more.
First, if your client code and API server are running on different domains or ports, configure CORS on your API server to only honor requests that originate from the client code's domain. Second, authenticate legitimate users so that only authorized requests for data are honored. There are lots of 3rd-party libraries to help with authentication.

Best Security Practices with Authorization Code Flow & React.js

I am building a project with both a web app built with React and Next.js and a native app built with React Native. I am looking for a second opinion on the best practice to handle Authorization for the Spotify API that will work on both platforms.
Option 1: Use the Authorization Code Flow with a proxy server to protect the client secret.
Native app passes authorization code to proxy server on heroku using GET request
Proxy server passes code, redirect_uri, grant_type, client_id, and client_secret to Spotify API
Proxy server passes back access_token, refresh_token, and expires_in to either web app or native app
Option 2: Use the Implicit Grant flow and accept that there is no
refresh_token. I would like to avoid this option if possible because the app will be making many requests and it would be more convenient to operate with a refresh_token.
My main concern is keeping the client_secret safe since my understanding is that React and React Native do not make requests server-side. Is it safe to pass back the access_token and refresh_token for a proxy?

Resources