So you want to use Discourse as an identity provider for your own web app? Great! Let’s get started.
Enable DiscourseConnect provider setting
Under Discourse admin site settings (/admin/site_settings) enable setting enable discourse connect provider
and add a secret string to discourse connect provider secrets
(used to hash SSO payloads).
Implement DiscourseConnect in your web app:
-
Generate a random nonce. Let’s call this value
NONCE
. Save it temporarily so that you can verify it with the nonce value that will be returned in the response. -
Create a new payload with the
NONCE
and aRETURN_URL
(where Discourse will redirect the user after verification). Payload should look like:nonce=NONCE&return_sso_url=RETURN_URL
. The host ofRETURN_URL
must match against the domain pattern you used when configuringdiscourse connect provider secrets
. -
Base64 encode the above raw payload. Let’s call this payload as
BASE64_PAYLOAD
-
URL encode the above
BASE64_PAYLOAD
. Let’s call this payload asURL_ENCODED_PAYLOAD
-
Generate a HMAC-SHA256 signature from
BASE64_PAYLOAD
using your sso provider secret as the key, then create a lower case hex string from this. Let’s call this signature asHEX_SIGNATURE
Send auth request to Discourse
Redirect the user to DISCOURSE_ROOT_URL/session/sso_provider?sso=URL_ENCODED_PAYLOAD&sig=HEX_SIGNATURE
Get response from Discourse:
If the above steps are done correctly Discourse will redirect the logged-in user to the provided RETURN_URL
. You will get query string parameters with sig
and sso
along with some user info. Now follow below steps:
-
Compute the HMAC-SHA256 of
sso
using sso provider secret as your key. -
Convert
sig
from it’s hex string representation back into bytes. -
Make sure the above two values are equal.
-
Base64 decode
sso
; you’ll get the passed embedded query string. This will have a key callednonce
whose value should match the nonce passed originally. Make sure that this is the case, and be sure to delete the nonce from your system. -
You’ll find this query string will also contain a bunch of user information. Use as you see fit.
That’s it. By now you should have set up your web app to use Discourse as SSO provider!
More Parameters, More Options
In addition to nonce
and return_sso_url
, the request payload has two additional optional parameters.
-
prompt
: Ifprompt=none
, then the SSO request is treated as a “just checking” request. If the browser/device is already logged-in to Discourse, Discourse will return a successful SSO response bearing user authentication information, as usual. If the browser/device is not already logged-in, then Discourse will not ask the user to log in, and will immediately return an SSO response bearing the parameterfailed=true
instead of user information. This provides a mechanism to query if the user is logged-in, without ever directing the user to a login dialog if they are not. -
logout
: Iflogout=true
, then the SSO request becomes a logout request. If a user is logged-in to Discourse on that browser/device, they will be logged out of that device. In either case, Discourse will immediately redirect back to thereturn_sso_url
, withoutsso
orsig
added to the query string.
prompt=none
and logout=true
are mutually-exclusive; it makes no sense to provide both in the same request.
sso=
Payload Reference
Request parameters:
-
nonce
: (string, required) a securely-generated random string -
return_sso_url
: (string, required) the URL to redirect back to with the response -
prompt
: (string, optional) Ifnone
, probe authentication status without prompting user to log-in. -
logout
: (boolean, defaultfalse
) Iftrue
, log the user out of Discourse.
Result parameters:
-
There is no
sso=
payload, or signature, in response to a logout request, just a redirect to the request’s plainreturn_sso_url
. -
The result payload for a login request will always contain the
nonce
, reflected from the request. -
The result payload will also reflect any other request parameters. Do not rely on this behavior; it is not necessarily intentional and not a guaranteed aspect of the API. (E.g., why is the
return_sso_url
parameter copied into the payload that is sent to thereturn_sso_url
?) -
If the request failed to authenticate a user, the result payload will contain
failed=true
. -
If the request succeeded in authenticating a user, the result payload will contain user credentials/information:
-
external_id
: (integer) Discourse id -
username
: (string) username/handle -
name
: (string) user’s real name -
email
: (string) email address -
avatar_url
: (string) URL to the original, unscaled image as uploaded by user -
admin
: (boolean)true
if user is an Admin, otherwisefalse
-
moderator
: (boolean)true
if user is a Moderator, otherwisefalse
-
groups
: (string) comma-separated list of groups (by name) to which the user belongs
name
andavatar_url
may be absent if the user never provided a real name or uploaded an avatar image. (Any element with anil
value within Discourse will be omitted from the response.) -
Discourse official “Using Discourse as identity provider” implementations:
- An http proxy (using golang) that uses Discourse SSO to authenticate users (only Admins): GitHub - discourse/discourse-auth-proxy: An http proxy that uses the DiscourseConnect protocol to authenticate users (made by @sam)
Community contributed “Using Discourse as SSO provider” implementations:
-
A PHP script that implements Discourse as SSO provider: Discourse sso provider login · GitHub (made by @paxmanchris)
-
Node.js:
GitHub - edhemphill/passport-discourse: A Passport strategy for authenticating using a Discourse forum
GitHub - ArmedGuy/discourse_sso_node: npm package for Discourse SSO login features. -
ASP.NET Core (only requires configuration):
GitHub - Biarity/DiscourseSso: Easy, configurable Discourse SSO: GET /auth/login -> recieve a JWT with user data -
MediaWiki extension (PHP):
DiscourseSsoConsumer, a SSO extension for MediaWiki (made by @mdoggydog)
Last edited by @JammyDodger 2024-05-26T07:20:55Z
Check document
Perform check on document: