OpenID Connect Authentication Plugin

official

(David Taylor) #1

discourse-openid-connect

discourse-openid-connect allows an OpenID Connect provider to be used as an authentication provider for Discourse. The plugin aims to provide a minimal implementation of the specification. Specifically, it supports the “Authorization Code Flow”. To get started, follow the plugin installation instructions, or contact your hosting provider.

Our oauth2-basic plugin can be used for connecting to some openid-connect providers (OpenID Connect is based on OAuth2). However, this plugin should require far less manual configuration, and can make use of the JWT “ID Token” if a JSON API is not available.

Configuration is automatically performed using an OpenID Connect Discovery Document. According to the specification, this should be located at <issuer domain>/.well-known/openid-configuration, but Discourse supports any path to allow for non-compliant implementations (e.g. Azure B2C). The discovery document is cached for 10 minutes, to improve performance on high-traffic sites.

If the discovery document includes a userinfo_endpoint parameter, then the plugin will use that to collect user metadata. If not, the plugin will extract metadata from the id_token (A JWT) supplied by the token endpoint. The plugin DOES NOT verify the authenticity of the JWT signature, as this would significantly increase complexity. This decision is supported by the specification:

If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature.

Basic Configuration Options

  • openid_connect_enabled: Enable OpenID Connect authentication

  • openid_connect_discovery_document: OpenID Connect discovery document URL. Normally located at https://your.domain/.well-known/openid-configuration

  • openid_connect_client_id: OpenID Connect client ID

  • openid_connect_client_secret: OpenID Connect client secret

  • openid_connect_authorize_scope: The scopes sent to the authorize endpoint. This must include ‘openid’

  • openid_connect_verbose_logging: Log detailed openid-connect authentication information to /logs. Keep this disabled during normal use.

Advanced Configuration Options

  • openid_connect_token_scope: The scopes sent when requesting the token endpoint. The official specification does not require this.

  • openid_connect_error_redirects: If the callback error_reason contains the first parameter, the user will be redirected to the URL in the second parameter. Used for unusual implementations that send errors in response to user input (e.g. Azure B2C)

  • openid_connect_allow_association_change: Allow users to disconnect and reconnect their Discourse accounts from the OpenID Connect provider

Example setup

Here we will set up the openid-connect plugin to connect to Google’s OpenID Connect provider. This replicates functionality that already exists in the core of Discourse, but it serves as an accessible example.

  1. Head to OpenID Connect  |  Google Identity Platform  |  Google Developers and follow the instructions to obtain OAuth Credentials.

  2. On the same page, follow the instructions to add a redirect URI. This should be https://<your_forum>/auth/oidc/callback (without a trailing slash)

  3. Go to your Discourse site settings and search for “openid_connect”

    • openid connect enabled:

    • openid connect discovery document: https://accounts.google.com/.well-known/openid-configuration

    • openid connect client id: <client-id>

    • openid connect client secret: <client-secret>

    • openid connect authorize scope: openid email (with a space in between)

  4. You’re done. The “Login with OpenID Connect” button will now log in using Google :tada:. These same steps can be applied to other providers, with very minimal changes.

Provider Specific Notes

Please feel free to update this if you find any provider-specific quirks relating to this integration:

Azure AD

Add the email scope, and make sure you’re using the version 2 endpoint configuration document. For example

https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
Azure B2C

The discovery document URL details can be found here: Web sign-in with OpenID Connect in Azure Active Directory B2C | Microsoft Docs


Support for OpenID Connect (OIDC)
Custom provider using OpenID Connect via IdentityServer3
Site wont rebuild
Sign in to Discourse using ORCID
Native SSO with Azure AD
Installing own gem in plugin
(Klāvs Priedītis) #2

The plugin works great for already registered users.
I’d like to get users signed up using the OpenIDConnect provider exclusively.

Am I correct to observe that this is an issue outside of the scope of this plugin?
Seems to me that Discourse can be set up to use 1 to N login methods, but supports only one sign-up method (either local or sso) even in cases where I disable every other login method except OpenID provider.

What would be the recommended way to allow sign-ups of only those users which are registered to my OpenID provider?

From what I found, I’d need to have an external sso service which would mediate the communication between Discource and my OpenID provider.

Please correct me if I’m wrong in my observations.


(David Taylor) #3

If you “log in” using OpenID connect (or any other authentication provider), and there is no existing account, you will be able to register via that method.

If you disable all other authentication methods, sign up will only be possible via OpenID Connect.

Does that solve what you’re trying to achieve? If not, maybe you can give an example of what behaviour you are expecting?


(Klāvs Priedītis) #4

I think we are on the same page in regards to my expectations.

I just found that the issue I have is
ActionDispatch::Cookies::CookieOverflow on /auth/oidc/callback.

It just happens to affect non-registered users.


(David Taylor) #5

I think I know what’s going on here - I’ll have a look in the next couple of days and let you know when it’s fixed.


(David Taylor) #6

The CookieOverflow issue should now be fixed - we now persist the data in the database rather than a cookie:

Please try updating to the latest version of Discourse, and try again. (this is a change to discourse core, not the plugin). Let me know if you’re still running into issues.


OAuth2 and Microsoft ADFS
(Klāvs Priedītis) #7

Thanks! It works now!

Now we can get back to the original problem:

Is there a way (without writing my own plugin or implementing Discourse sso service) to prevent users from signing up, except when they already have an account with my OpenID provider?


(David Taylor) #8

Yes, just disable the enable local logins setting in your site settings. That will make the login and signup buttons connect directly to your openid-connect provider.


(Andy Czerwonka) #10

Just wanted to let everyone know that this plugin works great for Azure AD. Just a few things to note:

  1. Make sure you use v2.0 of the configuration endpoint as per the notes above. The default v1.0 endpoint does not support email or profile scope.
  2. If there are issues with the client secret, try generating a new one. We had some issues, but after generating a couple it seemed just fine.
  3. Make sure you turn on “Sign in and read user profile” as a “Delegated Permission” in Azure AD when creating the entry for your site.
  4. Make sure you add the correct callback, which is ‘https://your-site/auth/oidc/callback

Huge thanks to @david for helping us get this working. He responded quickly with a new logging feature that really helped when troubleshooting issues. We might have abandoned it if we weren’t able to see what was going on.


Discourse-azure-oauth2 -- version token support
Discourse-azure-oauth2 -- version token support
Discourse-azure-oauth2 -- version token support
(Benjamin Miller) #13

Are there any plans on promoting this to a basic or advanced plugin?


(Erik Sundell) #17

Thank you so much for this plugin @david! It is just excellent!

It would be very powerful if I could utilize information in a groups claim to the belonging of groups in discourse, returned by requesting a groups scope.

Example

My OIDC provider (Okta) will if I provide it with an scope of groups return a claim called groups containing a comma separated list of names of Okta groups. I would be delighted if there would be a way to have a way to automatically assign a user to a group based on information returned in this claim.

For example, if you create a new group, you can see the following settings for email domain -> group assignment. I’d love to see a similar system for group assignment.