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
Related
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.
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.
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 :)
I am currently working on a mobile application that will allow a user to sign in via username/password (OAuth 2.0 Password Grant), Facebook, Twitter, or Google. The backend for this mobile application is coded in Spring Boot/Cloud (Java) and makes use of Microservices principles. I have several small services that are discoverable via Eureka and make use of Spring Cloud Config for centralized configuration. They are all exposed to the Mobile device using Spring Cloud Zuul, which acts as a reverse proxy. The Spring Security OAuth 2.0 setup that I have takes in the username and password then returns a JWT token, this token is validated every time a request is made to the backend. I also store users locally in MongoDB and make use of Method Level Security. I want to add Social Login to my application and have it do the following:
On the Mobile Device do the OAuth dance and get an access token
Send the access token to the server, and using Spring Social create a new User locally and associate it to Facebook/Twitter/Google, and then return a JWT token that can be used to validate requests
This JWT token should be created by Spring Security, and I should still be able to use Method Level Security and have local users
Basically I want all the features I have with my custom Spring Security OAuth 2.0 Password Grant with Social Login
This is my first attempt in architecting a system, and therefore am looking forward to responses from those with much more experience than I have. I have seen many examples that use Spring Social, but all of them are for Web Apps, not for Mobile, this is where I am currently stuck at.
The questions I have are the following:
Is my suggested approach adequate? Are there other approaches that are stateless and better for mobile applications?
Is Spring Security OAuth 2.0 and Spring Social Security enough to accomplish this? If so, are there resources that I can use? I have not found many online.
Could Spring Cloud Security be used as a solution?
Should I consider using a 3rd Party provider for Authentication such as Auth0 or OKTA?
using OAuth2 for a stateless solution is in my opionion adequate, because of:
oauth2 in general is a protocol designed to be usable in every client, which is able to perform http requests. Since the social nets you mentioned all support OAuth2. If everything goes bad, you still can consume them manually respecting the oauth2 specs, which they implement.
in general I see a problem with "authenticate with XXX and use that token as JWT for my requests". This is not directly possible, because that token is for their resource servers. Instead you need to separate 2 processes: authentication and authorization. In short you can use the socials endpoints to authenticate a user in your backend, which leads to a second oauth2 generation from your authorization server. This can create a JWT using all features from spring-oauth.
This libary should used in addition, since it helps to setup a application wide security solution. As example, you keep an own authorizationserver (which authenticates using social login) and several resource servers. spring-cloud-security helps to build things on top of that, as Zuul SSO, hystrix+ribbon powered feign clients respecting oauth2 authentications and so on
I don't thing this will help you, because those services primary serve you as an identity provider, while you are going to couple your users identity over social networks
I hope I could clarify your question in some way
I have achieved it by referring two spring example applications. Check this
steps, you will be able to achieve social sso login with Zuul, Auth-server and multiple back-end REST projects.
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.