Using OAuth to add authentication to a React app(fusionauth.io)
fusionauth.io
Using OAuth to add authentication to a React app
https://fusionauth.io/blog/2021/11/11/how-to-authenticate-your-react-app/
24 comments
Appreciate the educational back-and-forth between interesting companies in here!
Having just done a review of auth vendors (including FusionAuth + Auth0), I think your product addresses a much simpler use-case. FusionAuth and Auth0 support complex multi-tenancy setups and tie that into enterprise SSO providers, and all that's configurable on a per-customer/application basis with logical separation inside the auth vendor. I don't believe you support that level of complexity yet.
The nitty-gritty of auth does suck for most projects/early startups, but once you start selling to mid-size customers (B2B) they'll demand features that require what FusionAuth/Auth0/similar competitors offer.
Having just done a review of auth vendors (including FusionAuth + Auth0), I think your product addresses a much simpler use-case. FusionAuth and Auth0 support complex multi-tenancy setups and tie that into enterprise SSO providers, and all that's configurable on a per-customer/application basis with logical separation inside the auth vendor. I don't believe you support that level of complexity yet.
The nitty-gritty of auth does suck for most projects/early startups, but once you start selling to mid-size customers (B2B) they'll demand features that require what FusionAuth/Auth0/similar competitors offer.
Yet :)
Indeed, we're still catching up on feature-completeness, especially for the B2B world. In 2022 we will be tackling organization onboarding, SAML SSO, roles and permissions, subscription management, and authorization (as it relates to permissions and subscriptions). Still just getting started...
Indeed, we're still catching up on feature-completeness, especially for the B2B world. In 2022 we will be tackling organization onboarding, SAML SSO, roles and permissions, subscription management, and authorization (as it relates to permissions and subscriptions). Still just getting started...
I'm old and now more of a team therapist than developer but i really want to get back to actually writing code and may take up svelte (based on the awesome discussion yesterday). I will be signing up for clerk.dev today, thank you for the post!
Having spent much of the past week wondering the same thing, I think I'm now in love with your product. Looking forward to giving it a try. Thanks for jumping into the page to tell us about it.
Hiya Colin!
Disclosure, I'm head of devrel at FusionAuth, as well as a co-worker of the author of the post.
We think there is value in separating identity in the way you describe for a number of reasons.
If you want to see a take on how we think about authentication, the Modern Guide to OAuth is a great article to read: https://fusionauth.io/learn/expert-advice/oauth/modern-guide... particularly the "OAuth modes" section.
Disclosure, I'm head of devrel at FusionAuth, as well as a co-worker of the author of the post.
We think there is value in separating identity in the way you describe for a number of reasons.
* While this tutorial is about one app, that isn't usually how things work beyond demo land. In most places you have more than one application authenticating against FusionAuth (a couple of custom apps, OSS software like forums, COTS like Zendesk). In this case, isolating identity to a single component allows you to manage it centrally and to, if needed, bolster security.
* If you use OAuth, you get access to a tremendous selection of libraries across different languages. Every language has an OAuth framework you can use.
* Developers can have portable skills. Sure, figuring out the Authorization Code grant can be a bit of a pain, but once you do it once, you can do it again and again.
* By standardizing on OAuth/OIDC, you can move between identity providers. Yes, there are differences at the edges, but you'll have more flexibility than if you code to say, Clerk. This may or may not be worthwhile.
I haven't taken a close look at clerk, but I'm not sure how you handle the multi application setup. It is likely that both FusionAuth and Clerk are approaching the same problems in different ways (which is fine!).If you want to see a take on how we think about authentication, the Modern Guide to OAuth is a great article to read: https://fusionauth.io/learn/expert-advice/oauth/modern-guide... particularly the "OAuth modes" section.
For multiple services, we've been seeing more and more services adopt JWT-based models for SSO. We have a Hasura integration where we'll generate the JWT necessary for authenticating queries:
https://docs.clerk.dev/integrations/hasura
In general, we're pushing for more use of short-lived JWTs to sync identities between trusted parties instead of OAuth. We think this is preferable because it can keep sessions synced, while OAuth tends to result in independent sessions.
Admittedly, we do not run an OpenID Connect server on behalf of our customers yet. This is on our roadmap and will be added soon, and there are definitely some services that we can't offer first-class integrations with until that happens.
Your other point about "every language has an OAuth framework" is well-taken. Our initial launch used something proprietary and this was an issue, but we recently switched to spec-compliant JWTs to benefit more from existing libraries. Here's an example of our current, standard token:
https://jwt.io/#token=eyJhbGciOiJSUzI1NiIsImtpZCI6Imluc18xcn...
In general, we're pushing for more use of short-lived JWTs to sync identities between trusted parties instead of OAuth. We think this is preferable because it can keep sessions synced, while OAuth tends to result in independent sessions.
Admittedly, we do not run an OpenID Connect server on behalf of our customers yet. This is on our roadmap and will be added soon, and there are definitely some services that we can't offer first-class integrations with until that happens.
Your other point about "every language has an OAuth framework" is well-taken. Our initial launch used something proprietary and this was an issue, but we recently switched to spec-compliant JWTs to benefit more from existing libraries. Here's an example of our current, standard token:
https://jwt.io/#token=eyJhbGciOiJSUzI1NiIsImtpZCI6Imluc18xcn...
When you say "JWT-based models for SSO" what do you mean? I'm a bit unclear.
FusionAuth works with GraphQL/Hasura as well, see this post from a community member: https://fusionauth.io/community/forum/topic/696/how-to-use-f...
> In general, we're pushing for more use of short-lived JWTs to sync identities between trusted parties instead of OAuth. We think this is preferable because it can keep sessions synced, while OAuth tends to result in independent sessions.
This is an interesting approach. Can you tell me more (or just point me to the docs)?
> Admittedly, we do not run an OpenID Connect server on behalf of our customers yet. This is on our roadmap and will be added soon...
That's great! I'm sure your customers will welcome the additional flexibility.
FusionAuth works with GraphQL/Hasura as well, see this post from a community member: https://fusionauth.io/community/forum/topic/696/how-to-use-f...
> In general, we're pushing for more use of short-lived JWTs to sync identities between trusted parties instead of OAuth. We think this is preferable because it can keep sessions synced, while OAuth tends to result in independent sessions.
This is an interesting approach. Can you tell me more (or just point me to the docs)?
> Admittedly, we do not run an OpenID Connect server on behalf of our customers yet. This is on our roadmap and will be added soon...
That's great! I'm sure your customers will welcome the additional flexibility.
I suggest to avoid flows that expose a token to the client. This example mentions PKCE quickly at the end. You should absolutely NOT use the described flow without PKCE.
That said, a much more secure solution is described in the link below. It's also known as "Token Handler" pattern. In a nutshell, keep all the secrets on the backend and also handle the code exchange and tokens on the server, hence the name of the pattern. Then, store the token in a secure cookie. It's way more secure than moving a token into the browser, where a dependency vulnerability could get access to it.
https://wundergraph.com/blog/authentication_for_nextjs_with_...
That said, a much more secure solution is described in the link below. It's also known as "Token Handler" pattern. In a nutshell, keep all the secrets on the backend and also handle the code exchange and tokens on the server, hence the name of the pattern. Then, store the token in a secure cookie. It's way more secure than moving a token into the browser, where a dependency vulnerability could get access to it.
https://wundergraph.com/blog/authentication_for_nextjs_with_...
> Then, store the token in a secure cookie. It's way more secure than moving a token into the browser, where a dependency vulnerability could get access to it.
Cookies are still in the browser so what difference are you specifically addressing or advocating
Cookies are still in the browser so what difference are you specifically addressing or advocating
Secure, encrypted, same site, http only cookies cannot be accessed by JavaScript.
Sign it as well!
For instance: https://github.com/gorilla/securecookie
Unless I'm missing something and the payload is effectively signed. Either way, I still like to have signing generically done at this level of abstraction. Then I can put whatever in there.
Sometimes the encrypted payload is also signed too - maybe with a per-user secret. Now "log out everywhere" is as simple as scrambling the user's secret, thus invalidating their cookies. Simple.
For instance: https://github.com/gorilla/securecookie
Unless I'm missing something and the payload is effectively signed. Either way, I still like to have signing generically done at this level of abstraction. Then I can put whatever in there.
Sometimes the encrypted payload is also signed too - maybe with a per-user secret. Now "log out everywhere" is as simple as scrambling the user's secret, thus invalidating their cookies. Simple.
Hmmm. This article explicitly uses an express server to avoid the token being sent to the client.
That said, if you must send a token to the browser because you don't want to manage sessions, we've seen folks have success storing the JWT in an HTTPOnly secure cookie.
Disclosure: am co-worker of the author.
That said, if you must send a token to the browser because you don't want to manage sessions, we've seen folks have success storing the JWT in an HTTPOnly secure cookie.
Disclosure: am co-worker of the author.
I just add oauth in my proxy using libapache2-mod-auth-openidc, and set a HTTP header to pass user info to the server (which only accepts connections from the proxy IPs)
You can write your application in react, php, perl, bash, c, or just manually answer to http calls for all I care.
You can write your application in react, php, perl, bash, c, or just manually answer to http calls for all I care.
I'm considering something similar for protecting some simple ML serving API endpoints. Just put a proxy in between.
Something like
https://github.com/gogatekeeper/gatekeeper/blob/master/docs/...
It's no problem to set up Django, but I don't want to have to separately protect all public endpoints.
Something like
https://github.com/gogatekeeper/gatekeeper/blob/master/docs/...
It's no problem to set up Django, but I don't want to have to separately protect all public endpoints.
do you have different backend servers for those endpoints?
Love the gateway pattern. It's something I just spent some time investigating for a client and it is really elegant.
How do you store the tokens that the OAuth server generates on successful authentication?
How do you store the tokens that the OAuth server generates on successful authentication?
I leave that the the module, I believe it uses client cookies by default, but I use a persistent server cache on disk (the session tokens are stored encrypted)
https://github.com/zmartzone/mod_auth_openidc/wiki/Session-m...
https://github.com/zmartzone/mod_auth_openidc/wiki/Session-m...
that's... very interesting, I never even thought about handling auth in this way (make a proxy do it). Granted, i haven't set up auth in an application in probably a decade so this may be SOP.
Using OAuth2 for solving first party sign in is such a pain. Synchronizing refresh token requests, storing sessions on top of your access token, going through a consent grant, making sure you use the right flow (implicit is out? auth code? with pkce? without?)
There is some really good open source software emerging like https://github.com/ory/kratos which has APIs for native app flows, single page apps, server side apps and doesn‘t rely on protocols intended for completely different things such as „allow CircleCI access to my Gitlab repositories“.
Is it really worth investing in OAuth2 these days just because Auth0 pours millions in marketing? I highly question it…
There is some really good open source software emerging like https://github.com/ory/kratos which has APIs for native app flows, single page apps, server side apps and doesn‘t rely on protocols intended for completely different things such as „allow CircleCI access to my Gitlab repositories“.
Is it really worth investing in OAuth2 these days just because Auth0 pours millions in marketing? I highly question it…
> Is it really worth investing in OAuth2 these days just because Auth0 pours millions in marketing? I highly question it…
I don't know your exact use case. But I did a presentation about OAuth in the real world for Denver Startup Week and there was a slide about why you should use OAuth.
I don't know your exact use case. But I did a presentation about OAuth in the real world for Denver Startup Week and there was a slide about why you should use OAuth.
* Standards based
* Sharp security minds designed it
* Lots of edge cases handled
* Interoperable
* Not perfect, but far better than if you aren't using Oauth
* Isolates sensitive user data like passwords or PII into a single server. Enforces separation of concerns and allows for single view of user (this benefit is not exclusive to OAuth, of course, but if you chose OAuth, you get it).
Disclosure: I work for FusionAuth, an auth service provider.To piggyback off of Dan, I'd also mention that there's a few other benefits of using OAuth. OAuth allows allows you to delegate all sorts of auth features to an external IdP, instead of handling them yourself like:
* Password management * SSO * A bunch of other features and security (MFA, Forgot password, breached passwords, brute force, password validation, threat detection, account takeover protection, etc.)
Another benefit of OAuth is once you use the OAuth authorization code grant in your app, you can swap out IdPs. So, that delegation pattern is really helpful for offloading the extra work of building Auth, and it can "plug and play" into any IdP that supports it.
At the end of the day, OAuth is the protocol that lets you delegate all the auth code to an external auth provider, instead of trying to build it all yourself.
* Password management * SSO * A bunch of other features and security (MFA, Forgot password, breached passwords, brute force, password validation, threat detection, account takeover protection, etc.)
Another benefit of OAuth is once you use the OAuth authorization code grant in your app, you can swap out IdPs. So, that delegation pattern is really helpful for offloading the extra work of building Auth, and it can "plug and play" into any IdP that supports it.
At the end of the day, OAuth is the protocol that lets you delegate all the auth code to an external auth provider, instead of trying to build it all yourself.
Hey vexcaustic, author of the article here. I agree, sometimes implementing OAuth2 can be rough. We promote it at FusionAuth because OAuth2 is standardized and secure, and has been tested in lots of different scenarios. I took a look at kratos, it looks sweet, thanks for the link. We've had some FusionAuth users use Ory OathKeeper with FusionAuth too. It is interesting to see the different solutions for user management and login security that are being developed.
I'm interested in why FusionAuth chose OAuth to share identity between localhost:${serverPort} and localhost:${fusionAuthPort}?
Auth0 does the same, and it's always struck me as misplaced. OAuth makes sense to me between two distinct parties, but the architecture here treats FusionAuth and the application as a single party. Meaning, when a user signs in through the FusionAuth form, they're actually signing in to the application.
That's not true of Google OAuth - if a user signs into Google, they're not automatically signed into every service where they've ever clicked "Sign in with Google".
We moved away from this model because it also makes it really hard for FusionAuth to manage the user's session on the developer's behalf. You can see in this writeup that the developer is asked to pull in express-session to manage the user's session on their own.
Our mindset is: since Clerk is same-site to the developer's server, we can manage the user's session on behalf of the developer. When dev's use clerk, they don't need to think about cookies or sessions at all, except to the extent that lifetimes are configurable in our dashboard.