Discourse OAuth2 Basic Support

:discourse2: Summary Discourse OAuth2 Basic supports basic OAuth2 providers, assuming they have a JSON API endpoint where user details can be retrieved by token.
:hammer_and_wrench: Repository Link https://github.com/discourse/discourse-oauth2-basic
:open_book: Install Guide How to install plugins in Discourse

Features

This plugin allows you to use a basic OAuth2 provider as authentication for Discourse. It should work with many providers, with the caveat that they must provide a JSON endpoint for retrieving information about the user you are logging in.

This is mainly useful for people who are using login providers that aren’t very popular. If you want to use Google, Facebook or Twitter, those are included out of the box and you don’t need this plugin. You can also look for other login providers in our Github Repo.

Configuration

Basic Configuration

  1. First, register your Discourse application with your OAuth2 provider. It will require a Redirect URI which will be:

    http://DISCOURSE_HOST/auth/oauth2_basic/callback

:information_source: Replace DISCOURSE_HOST with the appropriate value, and make sure you are using https if enabled. The OAuth2 provider should supply you with a client ID and secret, as well as a couple of URLs.

  1. Visit your AdminSettingsLogin and fill in the basic configuration for the OAuth2 provider:
  • oauth2_enabled - check this off to enable the feature
  • oauth2_client_id - the client ID from your provider
  • oauth2_client_secret - the client secret from your provider
  • oauth2_authorize_url - your provider’s authorization URL
  • oauth2_token_url - your provider’s token URL.

:information_source: If you can’t figure out the values for the above settings, check the developer documentation from your provider or contact their customer support.

Configuring the JSON User Endpoint

Discourse is now capable of receiving an authorization token from your OAuth2 provider. Unfortunately, Discourse requires more information to be able to complete the authentication.

We require an API endpoint that can be contacted to retrieve information about the user based on the token.

For example, the OAuth2 provider SoundCloud provides such a URL. If you have an OAuth2 token for SoundCloud, you can make a GET request to https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN and will get back a JSON object containing information on the user.

To configure this on Discourse, we need to set the value of the oauth2_user_json_url setting. In this case, we’ll input the value of:

https://api.soundcloud.com/me?oauth_token=:token

The part with :token tells Discourse that it needs to replace that value with the authorization token it received when the authentication completed.

There is one last step to complete. We need to tell Discourse what attributes are available in the JSON it received. Here’s a sample response from SoundCloud:

{
  "id": 3207,
  "permalink": "jwagener",
  "username": "Johannes Wagener",
  "uri": "https://api.soundcloud.com/users/3207",
  "permalink_url": "http://soundcloud.com/jwagener",
  "avatar_url": "http://i1.sndcdn.com/avatars-000001552142-pbw8yd-large.jpg?142a848",
  "country": "Germany",
  "full_name": "Johannes Wagener",
  "city": "Berlin"
}

The oauth2_json_user_id_path, oauth2_json_username_path, oauth2_json_name_path and oauth2_json_email_path variables should be set to point to the appropriate attributes in the JSON.

The only mandatory attribute is id - we need that so when the user logs on in the future that we can pull up the correct account. The others are great if available – they will make the signup process faster for the user as they will be pre-populated in the form.

Here’s how I configured the JSON path settings:

  oauth2_json_user_id_path: 'id'
  oauth2_json_username_path: 'permalink'
  oauth2_json_name_path: 'full_name'

I used permalink because it seems more similar to what Discourse expects for a username than the username in their JSON. Notice I omitted the email path: SoundCloud do not provide an email so the user will have to provide and verify this when they sign up the first time on Discourse.

If the properties you want from your JSON object are nested, you can use periods. So for example if the API returned a different structure like this:

{
  "user": {
    "id": 1234,
    "email": {
      "address": "test@example.com"
    }
  }
}

You could use user.id for the oauth2_json_user_id_path and user.email.address for oauth2_json_email_path.

If the key itself includes periods, you will need to put double quotes around it, or escape the periods with a backslash. For example, given this JSON:

{
  "example.com/uid": "myuid"
}

You would specify the path as example\.com/uid or "example.com/uid"

:warning: If you set oauth2_json_email_path, the OAuth2 provider must confirm the user owns that email address. Failure to do this can result in account takeover in Discourse!

CHANGELOG

  • 2019-03-01 A new site setting has been added to allow email addresses to be updated on Oauth2 login. The setting is called oauth2_overrides_email .
25 Likes
Keycloak with Discourse
Login from another user database
Shopify Integration
Discord Oauth2 Plugin
Discourse SSO with OAuth2
OAuth2 integration with Drupal
How can we enable Auth0 SSO in Discourse
How to login to discourse from external website
Custom Login / Registration from another API
Login on discourse using mastodon credentials
Example code for how a hosted solution would integrate with discourse
Login flow (Flask -> Discourse -> Flask) with OAuth
OAuth connection of discourse
How to use Oauth2 service provided by discourse?
Open source will support customized provider SSO
OAuth2 Custom Redirects Plugin
How to force users link phone number when they using Discourse?
Discourse OpenID Connect
Set up Salesforce auth using OAuth2 basic support plugin
Is "partial" SSO possible?
ADFS Authentication
Suggestion for improving Integrated Authentication development
Github and Twitter Login/Sign-Up Functionality?
Shopify Integration
SSO with TownNews CMS
Removing Yahoo login from Core, and deprecating OpenID 2.0
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin
Oauth2 with fusionauth cert issues
Automatically creating a user when logging in with Webflow/Memberspace
[Invalid] Omniauth callback does not support POST, only GET
Migrate a Jive Clearspace forum to Discourse
Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso)
Error during SSO integration - Wholistic Minds
Discourse + Intercom (Current User Id)
Switching out authentication for a passwordless alternative
Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso)
Discourse for self hosting
OAuth2 integration with Drupal
Drupal 8 and Discourse shared SSO

Hi Robin, quick question:

The callback URL I have been using is https://1.hosted-by-discourse.com/auth/oauth2_basic/callback - and it doesn’t seem to be working. Does it look like I’m doing anything wrong?

What is supposed to go in “DISCOURSE_HOST”? I am currently using the Discourse hosting free trial so for the “DISCOURSE_HOST” section I am using the Discourse hosting URL - which looks like this 1.hosted-by-discourse.com

Thanks

You need to use your public site URL (whatever appears in the address bar of your browser). The *.hosted-by-discourse.com addresses are our CNAME targets, and cannot be accessed directly.

Ok, thanks David, we’ll try that and let you know how it goes by tomorrow :slight_smile:

The new callback URL worked!

But I do have another question - is it ok to leave these 2 fields (below) empty if the response to my token request doesn’t have any property such as a user id?

As you can see, I am using (or at least trying to) use the “Fetch user JSON for OAuth2” method, so I guess we can fetch the user id from that user info JSON response?

Ty!

1 Like

Yup, you can leave both of those settings blank :+1:

1 Like

Hi everyone, I just setup another topic in which I want to understand, how to setup everything for Auth0 (which already works in vanilla style), but “nicer” according to my needs.

Since I thought it is a separate topic, I created this one here. Would be great, if you could check it out. :slight_smile:

Love this plugin, thank you so much!

Managed to get this working with roblox beta auth 2.0:

Hello,
We are trying to integrate Discourse with our application using OAuth2 Basic but we are getting the following error in the logs:
Note: We are using NGROK as we are debugging the connection.

OAuth2 Debugging: request POST https://formshare.ngrok.io/oauth2/token

Headers: {"User-Agent"=>"Faraday v1.9.3", "Content-Type"=>"application/x-www-form-urlencoded", "Authorization"=>"Basic S2k2SFZtTVpuSTFHUExiRXVlWVJDNENiOkNvb1k0anlQemt3dWNRV21Sa2FWOVNnbHZLbjJFT3cxc3BIMmtMck9yY21vNDM4Tg=="}

Body: {"client_id"=>"Ki6HVmMZnI1GPLbEueYRC4Cb", "client_secret"=>"...some_secret_...", "grant_type"=>"authorization_code", "code"=>"5pPCrsp0pZ84373MNaHh2cuskfc8AlbfmdwMBFIVW4n4z9aX", :redirect_uri=>"https://community.formshare.org/auth/oauth2_basic/callback"}

------------------

OAuth2 Debugging: response status 200

From POST https://formshare.ngrok.io/oauth2/token

Headers: {"content-length"=>"108", "content-type"=>"text/html; charset=UTF-8", "date"=>"Thu, 01 Sep 2022 21:42:08 GMT", "ngrok-trace-id"=>"79cdc3f1c3eae5e37a30796aebbf9bd6", "server"=>"gunicorn"}

Body: {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

-----------------------------------

(oauth2_basic) Authentication failure! invalid_credentials: OAuth2::Error, {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

We left the params “oauth2 callback user id path” and " oauth2 callback user info paths" empty.

Any idea is appreciated.

Can I use this to authenticate with Microsofts XBL service?

I presume the logic would be similar to this?