I was able to use this to create an account linking system for my Minecraft server! Thought I’d share what it looks like! This was my first time working with Discourse SSO, so I might’ve overcomplicated everything. However, it works, which is the main thing.
Hi i did all these correctly. but when the user is not logged in discourse it will show user login popup. when I fill username and password, it does not redirect me back to return_url. can you please help me?
I assume the nonce
is there to prevent replay attacks. I read online that replay attacks aren’t possible with HTTPS, which is what I’m using. So do I still need to do the nonce? I ask because I’m not sure where to store it. Does it make sense to store it as a secure, plain text cookie in the user’s browser? and then read it from the browser along with the return payload?
This library, which is linked from the original post GitHub - ArmedGuy/discourse_sso_node: npm package for Discourse SSO login features. doesn’t use the nonce when validating the user.
Yes, you still need to validate the nonce because it prevents reusing payloads that Discourse sends when it redirects users back to your site.
For example, let’s your site has some content behind a paywall that only members of the subscribers
group on Discourse can access and you use the groups
field in the payload that Discourse sends to your site to display the paid content only to members of the subscribers
group. If you don’t validate the nonce, a user who is no longer in the subscribers
could use an old payload from when they were a member to login to your site and see the paid content.
It’s best to store the nonce in a database with a short expiration date and delete the nonce from the database as soon as it’s used. However, if you can’t use a database, then you can use a cookie to store the nonce, but you need to do some additional steps to prevent payload reuse:
- attach an expiration date to the nonce when you generate it, for example 10 minutes from the current time
- sign the whole cookie (nonce + expiration date) to prevent users from modifying the nonce and/or the expiration date
- verify the signature of the cookie and ensure the nonce isn’t expired
That should give you a good enough protection against payload reuse. Keep in mind that technically it remains possible to reuse a payload, but it’ll be limited to a 10 minutes window instead of forever.
A simpler solution that doesn’t need a cookie is to include the expiration date in a custom field in the payload that you generate. Then when Discourse redirects users back to your site with a payload, your custom fields will be included and you can retrieve the expiration date and you verify it’s not expired. To include a custom field in the payload, you need to include a field prefixed with custom.
, so your payload would look like this:
nonce=NONCE&return_sso_url=RETURN_URL&custom.expiration_date=TIMESTAMP
You could also store the nonce in the session, that will prevent the user from tampering with it as well.
Just circling back to this thread years later
Can someone tell me (@pfaffman or @tobiaseigen or @iamntz) what the Discourse SSO provider returns? I know I can “try it and see” but it would be nice to have it documented. The github PHP sample code doesn’t trally have any other fields even mentioned.
Ideally, it would send the same fields as when Discourse uses the external script for SSO, such as external id, email, username, name, avatar photo etc. So we can import this and create a user on our side!
Does it also tell Wordpress the email?
How about groups, badges etc? Can we find this information by making REST calls?
Finally, what about the user’s private messages and other stuff? I guess if Discord was an oAuth provider and allowed our apps to consume this sruff, that would be awesome.
When trying to enable Discourse Connect I get this error:
enable_discourse_connect: You cannot enable DiscourseConnect and invite only at the same time.
Any ideas?
I see you have asked the same question here: Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso) - #537 by Roie_Natan. If you are trying to configure the enable discourse connect
setting and not the enable discourse connect provider
setting, the other topic is the correct place to ask your question.
The enable discourse connect provider
setting is for when you want to use your Discourse site as the identity provider for another site. The enable discourse connect
setting is for when you want to log users into Discourse via an external site.
I’ve implemented the procedure in Python for a Flask application I am building. Here is some boilerplate code for anyone who needs it. The steps laid out in this topic were pretty simple to follow but I’m not a security specialist so if I overlooked anything please let me know!
We are trying to implement using Discourse as an SSO provider and what we do not understand is how does Discourse know which user needs to be verified? So the directions say: “Create a new payload with nonce and return url”. But when you post this via a fetch to Discourse, how does Discourse know what user to check to see if they are logged in? Sorry, if this sounds like a stupid question, but I just cant understand how this is working and I’ve worked with alot of Auth systems over the years, so somewhat familiar. Is the user email we are trying to check the login status for, need to be included in the payload sent to Discourse? If so, what is the exact structure of the payload that needs to be sent to Discourse. If not, again what is Discourse is checking exactly? My assumption is that we ask the user for their email on our end, and then send the payload with email to Discourse to see if that particular user is logged in, but this is not wha the directions say, so I’m totally confused. thanks for any help.
Never mind. We figured this out. We thought the SSO URL need to be sent as a POST request to the Discourse instance and then receive a response. Now we see this is a redirect to Discourse, and then Discourse then redirects back to our site. So it’s clear now what to do. Sorry for previous post.
FYI/FWIW: I submitted a PR to allow for a prompt=none
parameter in the auth request. Similar to a feature in the OpenID Connect protocol, this allows an SSO consumer to probe whether or not a user/client is already logged in, without sending them to a login dialog if they are not.
The PR has been waiting for a final review by someone on the Discourse team for about 8 weeks now; it does seem quite a bit longer than I would expect.
Hi @mdoggydog - sorry for the very long delay here!
I’ve just reviewed and merged the PR - thanks for the contribution!
Yay! Thank you, @david.
As promised, I just updated the wiki article here to include a description of the new parameter (and the earlier new logout
parameter, and to fix some minor typos/grammar, and to add a reference section documenting the sso=
payload as I understand it from having dug around in the source code).
I want to stop using our website to serve as the SSO for Discourse and instead use Discourse’s built-in login tools to limit access to certain materials on our website.
I think the right tool to use is: GitHub - discourse/discourse-auth-proxy: An http proxy that uses the DiscourseConnect protocol to authenticate users
I haven’t found any extensive instructions on how to use it.
Can I install that in the same DigitalOcean droplet as our Discourse site, or do I need to host it somewhere else?
Edit: bolded my question
Any help on the above question? Use Discourse as an identity provider (SSO, DiscourseConnect) - #148 by alehandrof
I’m setting as the return_sso_url
a URL which itself has a query parameter:
http://localhost:7000/completeLogin?returnto=%2F
The payload I send to /session/sso_provider
as the sso
parameter looks like this prior to base64-encoding:
nonce=ENIwf0bElViDu325dTd6&return_sso_url=http://localhost:7000/completeLogin?returnto=%2F
The URL Discourse actually redirects to after authentication is this (with the sso
and sig
parameters abbreviated):
http://localhost:7000/completeLogin?returnto=/&sso=...&sig=...
What surprises me here is that the query string I set for return_sso_url
appears to have been urldecoded by something, because it has returnto=/
instead of returnto=%2F
. The value of return_sso_url
I find inside sso
after base64-decoding it also has a slash instead of %2F
.
Is that what I should expect to happen? (If so, why?) Is this a bug in Discourse?
What’s the reason that the sso
payload contains avatar_url
instead of avatar_template
as is returned in /u/{username}.json
and /session/current.json
?
avatar_url
isn’t present for uses who haven’t set an avatar, whereas avatar_template
contains the leter_avatar_proxy
path actually used in Discourse to show avatars for those users, and avatar_url
points to the raw avatar image instead of one scaled to the desired size for uses who have set an avatar.
It seems to me that avatar_template
is what anyone who intends to use the avatar information contained in sso
will want—but then will need to make an additional API request to get it.
Right now I am implementing SSO in my app, login works very good so far, logout is not.
My Discourse Instance is redirecting correctly back to the return URL without any sso or sig parameter, but when I open Discourse, my Account is still logged in.
Any idea?
I’m assuming you are using the Discourse logout redirect
site setting to redirect users back to your app after they logout from Discourse.
A possible cause of the issue would be if the login required
setting is enabled on your Discourse site. When that setting is enabled, Discourse will automatically redirect unauthenticated users to the SSO provider site if they have gone directly to the Discourse site. That means that unless you are logging users out of your app in when they are first redirected to the logout redirect
url, they will be automatically logged into Discourse the next time they visit the site. You can confirm this behavior by going through the process with your browser’s inspector open to its network tab.
In case it’s useful, here’s how the WP Discourse plugin handles the Discourse logout redirect: wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub.