OAuth client secrets in React apps - reactjs

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.

Related

React SPA with oidc-client and client secret

I'm building a React SPA on top of a ASP.NET Core API and I want to authenticate with OIDC. Grant type is authorization code and the client does have a client secret.
Since we will be using a client secret, the authorization step that involves the secret has to go through a proxy that we control.
Is this doable in a React SPA with oidc-client?
If the secret is in the client, it's not a secret. :)
Secrets are for server-server authentication, because the secret is secure on a server (we hope so, anyway) and the API granting access has a whitelist of consumers it's granted access to use the secret.
For a SPA, if you're talking about allowing an app to use an API, I believe you're limited to using a CORS whitelist. If you're talking about a user accessing the API via the client, then you're looking at access codes and usernames/password.
PROBLEM
You have a blocking issue with the authentication system, or with usability or getting security to an acceptable level. In your case there is no PKCE support.
PROXYING SOLUTION
Use oidc-client which will add PKCE parameters and your SPA security supports the latest standards.
The client secret will come into play during the authorization code grant and refresh token grant messages.
Messages can be adapted server side to remove PKCE and use a client secret instead. It is quite a complex solution though and not everyone will like it.
It requires a SameSite cookie issued by the web domain. In my case I used an AWS lambda edge function that runs within a CloudFront content delivery network.
WHY DO IT THIS WAY?
In order to fit into an SPA architecture and meet wider goals in areas such as usability, coding model, mobile integration and global web performance. Depends if you feel it is worth the effort.
LINKS
Architecture Goals
Design Pattern
Code Sample you can run
Online AWS SPA
Proxying details

OpenID Connect /Node /React

There is a lot of examples how to implement OpenID Connect auth. in Node - code grant (+ client password).
There is a lot of examples how to implement OpenID in React (SPA) - code grant with PKCE
Even I know that PKCE it's rather secure, however I feel bad to relegate authentication solely on client side.
Every React SPA has backend (at least it should be hosted somewhere).
I want to have server side in Node (Express) to securely save client password and make all heavy lifting with Identity Server and
React for front-end.
As I already said there is a lot of examples of "Node (Express) with template engines" for authentication.
But I want to use React as "template engine".
So, I am looking for full and correct implementation of it. Meanwhile I cannot find it.
Can anybody help me with it - to find an example?
You need some actual protection in the SPA / browser though, and the 2 common options are:
Plug in OIDC Client Library to do the heavy lifting, so that you don't write much security code yourself. This library runs a number of strict security checks before accepting tokens.
Use a proxying solution that results in your SPA getting a cookie.
For an SPA this tends to be a more of a home grown solution rather than a standards based one
RESOURCES OF MINE FOR OPTION 1
SPA Security Code
Explanatory Notes
FOR OPTION 2
You could use the Open Id Client Node JS Library server side, and follow it's guidance.
I've found 2 solution on the Internet.
The First :
Implement social authentication with React + RESTful API
On the frontend, get the 3rd party app’s login popup to appear.
(Still on the frontend) Grab the authentication token the 3rd party app returns after >agreeing to login.
(Yep, still frontend) Send that token to the backend as part of the body of your >request. (I like to use Blobs, but that’s just me.)
On the backend, verify the token.
If the token is authentic, you will receive the user as part of the verification >response (at least that’s the case with Passport.js, which we’ll be using).
Save the user’s data to your database.
Return a JWT token to the frontend. What you do with that token is out of scope for >this tutorial, but it should probably be used to authenticate each of the logged in >user’s actions.
Very well explained, with github working example social-auth-example
It's only for social authentications, but I think no problem to make something more general or at least to add my OpenID Connect Auth. provider.
The second example:
React Authentication with Twitter, Google, Facebook and Github
This approach uses socket.io. Very interesting.
P.S.
So, I need to figure out what solution is more secure and if there any security breaches.
Not easy task to do. It's so pity, there is no standard flow for my problem. I can find 1000 reasons why it's better to make all heavy lifting on back-end and not to rely on OIDC Client Library. The first reason is my boss :)

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.

Securing a React frontend and with Python API using AWS Cognito

I'm considering using AWS Cognito as a user management system for a single page web app I'm building using React along with a Python REST API backend (Pyramid). I'm struggling to see how all the pieces fit together for my architecture (the docs don't seem to be helping me). There are many great examples of how to implement authentication into the frontend using JS. My issue is how to integrate this authentication into my backend REST API.
In my current hand rolled user management system, the frontend calls the REST API on sign-in and is given a token which is passed to API again for every subsequent request. I'm then able to use ACL's on my API functions, check permissions to access resources, etc. If I were to use Cognito and perform the authentication on the frontend (as many examples do) how will my backend know if the token is valid when it receives it with a request? Surely I wont have to call Coginto from the backend to verify this for every request? Also how can I perform checks for information such as 'is this user in the admin group' if that group is defined within Cognito? Again, calling out to Cognito for every request seems very heavyweight and cumbersome.
I did see one example where a list of valid tokens was exported from Cognito as a JSON file and kept on the backend. This seems horribly static when users could be added and removed regularly.
Is Cognito really suitable for my use case? Some high level guidance and pointers to any relevant examples and docs would be greatly appreciated!
When authenticating with Cognito, the user can have 3 tokens:
Refresh
Access
ID
For python, boto3 can interface now with Cognito. There's also this python lib wrapper: warrant, to make it easier.
Once you have the token, it is possible to pass it to the API (eg: access) and it can be checked on the server side with python-jose, as per AWS docs
To pass the token, an example pyramid /login implementation can keep the information in the session before setting the request response:
request.session['my_token'] = str(a_token)
The default cookie session factory works, though it warns that the token is not sent encrypted.

What OpenID Connect authorization flow to authenticate mobile app users?

I am building a cross-platform mobile app that interacts with a RESTful API, and I want to use OpenID Connect to authenticate my users. I will be building my own OpenID Connect provider server.
OpenID.net claims that:
OpenID Connect allows for clients of all types, including browser-based JavaScript and native mobile apps, to launch sign-in flows and receive verifiable assertions about the identity of signed-in users.
However, I can't find any documentation explaining how to actually authenticate for a mobile app client.
This StackExchange answer makes it clear that OpenID Connect does not support the "resource owner password-based grant" flow or the "client credentials" flow.
That just leaves the "authorization code" flow (normally used by server-side apps) and the "implicit grant" flow (normally used by client-side apps). Both of these seem to rely on redirecting the user to the provider's authorisation endpoint, and having the provider redirect back to the client URL. I don't see how this can apply to a mobile app.
Can anyone explain to me (or even better, point me at a tutorial or some example code) which explains how to do this?
Update
To clarify: OpenID Connect relies on the client redirecting the user to the Authorization Endpoint, and then the provider redirecting the user back to the client. In the case where the client isn't a web app, how can this work?
Mobile apps, at least on iOS and Android, can register custom URL schemes so that a redirect from a browser can send the user back to your app along with some query parameters.
So, you can use these flows in a native mobile app, but it involves sending the user to a web browser (either an external browser app or a web view built into your application) in order for them to authenticate with the OP.
A complete article presenting how to implement the "Authorization Code Grant" flow securely on a native mobile app is available here : Building an OpenID Connect flow for mobile. It is based on latest IETF OAuth 2.0 Security Best Current Practice.
Please also note that the use of the "Implicit Grant" flow is now highly discouraged.
I think that the Hybrid flow from the OpenID Connect spec is probably the one which you want to use. OpenID Connect Core Spec.
This does rely upon having a configured return URI, but as James says you would use a custom URI scheme to enable the mobile OS to redirect after login to your own app. Your app would then have an access code which it can use to obtain access tokens as needed (assuming that you are using Oauth2 to protect your back-end API services which the mobile app uses).
There is a vulnerability which would allow a malicious app to hijack your URI scheme and grab the tokens, There is a draft spec to overcome that Proof Key for Code Exchange by OAuth Public Clients which is worth considering implementing.
Using an app scheme URL is the correct answer as noted above. I wanted to add additional clarification since some responses above include links to an article that makes incomplete assertions about a compliant SSO design, and make it unnecessarily complicated for a simple SSO use case. I think google's model is secure and so I might model OIDC interactions with a homegrown IDP after how theirs works.
https://medium.com/klaxit-techblog/openid-connect-for-mobile-apps-fcce3ec3472
The design in this article linked above, as depicted in the diagram on the article, does not work for google's oAuth/OIDC implementation on Android. There are two reasons for this:
Google will not vend any client_secret for an oAuth client that is typed "Android"
Suppose I switch to "Web" application which does have a secret: Google will not allow a redirect_uri other than 'http' or 'https' for an oAuth client that is typed "Web"
Instead, google officially recommends letting the typical mobile flow (and you should also be using PKCE) drop an ID Token on the client, who can then exchange it for a session with the App server:
https://developers.google.com/identity/sign-in/android/backend-auth
This is secure because your IDP should be signing the JWT ID Token with a private key so it can be validated by your system's apps/services and used to assert validated (unexpired) identity intended for a particular OIDC client & audience.
** Do not pass ID Token as authorization on every request, but rather exchange it once with your backend for a secure session context as managed by your application.
Check out MITREid project on github:
MITREid Connect
This project contains an OpenID Connect reference implementation in
Java on the Spring platform, including a functioning server library,
deployable server package, client (RP) library, and general utility
libraries. The server can be used as an OpenID Connect Identity
Provider as well as a general-purpose OAuth 2.0 Authorization Server.

Resources