Discourse SSO with Auth0 🚀
TL;DR
You can achieve a very seamless SSO experience with Discourse and Auth0 using one of the best features Auth0 has: rules. Check the “Implementation” section for the code.
Background
I don’t know you but I discovered Discourse a while back when I selected it to be part of the online platform for the new political party we are creating in Uruguay based on ICT.
We needed an easy way people can engage talking and discussing about ideas to be part of the Government Programme. It needed to be something familiar for people, like a forum but adapted to this era. It fitted perfectly.
Now, I also had the fantastic idea (modesty aside) to use a service to handle all the users in order to have a consistent experience throughout all the tools in the platform. Something easy to configure, vast to customize and most importantly, free of charge, as we are just growing and we just get funding based on donations (check out OpenCollective, very recommended). That’s why I decided to use Auth0. Very neat service which supports open source projects like the political party I work for and support.
So, anyway, although there is a nice Discourse plugin to hook up Auth0 authentication, I always struggled with how it handled the creation of a user which needed to be re-created in Discurse database to work. What’s the point of having a super user handling service if at the end the user needs to tackle a user creation dialog on Discourse?
Understanding the problem
After a while trying to understand how stuff worked on both ends, Discourse and Auth0, I got the idea of implementing what Discourse needed on Auth0’s side.
When I say a while trying to understand how stuff worked on both ends, I mean submitting a bunch of questions which got very good answers most of the times.
These are some of my attemps:
And that last one was key for the finding relevant to this blog post.
Thanks to Michael Brown’s super neat reply with the following diagrams, I got the realization that something could be done from the authentication service side.
What a journey! But anyway, here comes the code.
Implementation
First of all, a big shoutout to Johan Jatko for creating the discourse-sso node.js package that simplified a lot of code for me to implement this.
This code goes into a new Auth0 rule which is going to be run when a user signs in from Discourse using SSO:
Please replace CLIENT_ID and DISCOURSE_URL with your information. And on line 10, context.clientMetadata.sso_secret is a variable (can be a just a string with the value but avoid doing that as much as possible) set on your Auth0 Client advanced configuration, like this:
Then, in your Discourse instance, under Settings > Login, you will find these options:
The important fields are:
- enable sso
- sso url: https://AUTH0_DOMAIN/authorize?client_id=CLIENT_ID&response_type=code
- sso secret: same as the one included in Auth0 Client variables above
The following ones are just to customize how SSO information from Auth0 can override Discourse information. I suggest enabling verbose sso logging so you can debug better any potential issues related to SSO.
Note: The rule you create to handle this flow will execute and then as the authentication attempt will stop there (no call to /continue?state=STATE_ID will happen), no other subsequent rule will execute, so mind the order of the rules.
Hope it helps someone as lost as I was đź‘Ť
And continue giving me feedback, don’t hesitate to let me know if you can think of any improvement.