Discourse OpenID Connect

:discourse2: Summary Discourse OpenID Connect allows an OpenID Connect provider to be used as an authentication provider for Discourse.
:hammer_and_wrench: Repository Link https://github.com/discourse/discourse-openid-connect
:open_book: Install Guide How to install plugins in Discourse

Features

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.

Configuration

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 rp initiated logout: Redirect the user to end_session_endpoint after logout. Must be supported by your identity provider and included in the discovery document.

  • openid connect rp initiated logout redirect: (optional) The post_logout_redirect_uri which will be passed to the logout endpoint. If provided, it must be registered with the identity provider.

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

  • openid_connect_use_pkce: Enable Proof Key for Code Exchange (PKCE) for OpenID Connect authentication.

  • 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  |  Authentication  |  Google for 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.

Debugging

In addition to the verbose_logging setting described above, you can access data about OIDC associations using the data-explorer plugin:

SELECT user_id, provider_name, provider_uid
FROM user_associated_accounts
WHERE provider_name = 'oidc'

Or on the rails console:

User.find_by_username("david").user_associated_accounts.where(provider_name: 'oidc')

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 - Azure Active Directory B2C | Microsoft Learn

To make emails work:

Yahoo
  1. Head to Yahoo and create a new app

  2. Enter the Application Name, and set the callback domain to your forum domain (e.g. meta.discourse.org)

  3. Under API Permissions, choose Profiles: Read/Write Public and Private. This is the only way I know of to obtain the user email address

  4. Save the app

  5. In the Discourse OIDC settings, set the discovery document to

    https://login.yahoo.com/.well-known/openid-configuration
    
  6. Enter the client ID and secret from Yahoo

  7. Enable the OIDC plugin

AWS Cognito
  1. Go to Cognito and select or create a new user pool.
  2. Define an app in App clients.
  3. Leave everything to default, but change Auth Flows Configuration to only select ALLOW_REFRESH_TOKEN_AUTH.
  4. Go to app client settings and select the new app.
  5. Change the callback URL to https://yoursite.example.com/auth/oidc/callback.
  6. Only check the Authorization code grant flow among “Allowed OAuth Flows”.
  7. Check all scopes needed (I have all checked).
Okta
  1. Configure Discourse with your Okta app client ID and secret

  2. Set the discovery document URL to

    https://{your-app}.okta.com/.well-known/openid-configuration
    
  3. In Discourse, set the openid connect authorize scope to openid email

:discourse2: Hosted by us? This plugin is available on our Business and Enterprise plans. OAuth 2.0 & OpenID Connect Support | Discourse - Civilized Discussion

Last edited by @david 2024-10-16T11:34:36Z

Check documentPerform check on document:
46 Likes

Hi there,
we are using the OpenID Connect Authentication Plugin with a Discourse installation on AWS.
We have deployed the containers Discourse, Discourse Sidekiq and Redis (Based on Bitnami but please don’t kick me out ;). The DB is running on AWS RDS. We use KeyCloak.

Things do run.

But sometimes after a restart of the Discourse AWS Task it happens that it thinks that it has the Discovery document in the cache but then there is no doc there. And it does not try to re-retrieve it from KeyCloak:

OIDC Log: Discovery document loaded from cache
OIDC Log: Discovery document is
---
(oidc) Request phase initiated.
(oidc) Authentication failure! openid_connect_discovery_error: OmniAuth::OpenIDConnect::DiscoveryError, Discovery document is missing

In the browser app I see: Unable to fetch configuration from identity provider. Please try again.

What can you advise ?

1 Like

Hello,

Is there a way to set the discourse user avatar source to a field which is specified in the openID service?

Edit: we’re using keycloak

Hello,

I have a requirement similar to @TomĂĄĆĄ_Guba one : I would like to get value from a custom entry in user profile and use it in a [custom] user field.

In my personal case, i have a discovery document with a userinfo_endpoint

Is there something like that in the plugin roadmap ?

Thanks

Hello, I managed to make the plugin work with my SSO openID but it doesn’t come filled in the username field of the other system or email among other fields


I imagine that I should configure something in the “openid connect claims” field, but I don’t know how to configure this field directly. Can someone give me an example? Here are some prints of how my project is:

1 Like

Is there a way to avoid “losing” the original route when logging in to a private post?

If we visit a private page and hit either of the login buttons on that page, when redirected back to the site, we end up on the categories page.

Hi @david,

Can you please take a look at the issue mentioned in following post? I would like to use OIDC plugin over OAuth basic. But I face the same issue - cannot pass parameters to /authorize request. I put the value in plugin in format of foo=bar.

I haven’t been able to get this to work in LinkedIn. Curious if anyone else has? I get as far as logging into LinkedIn after being redirected there when clicking on the signin with
button and then “allowing” my app to use my email from LinkedIn, then I get “Sorry there was an error authorizing your account. Please try again.”

https:/discourse.mysite.com/auth/failure?message=invalid_credentials&origin=https%3A%2F%2Fdiscourse.mysite.com%2F&strategy=oidc

I’m still having trouble with this. I’m getting the following error:

(oidc) Authentication failure! invalid_credentials: OAuth2::Error, invalid_request: A required parameter "client_secret" is missing {"error":"invalid_request","error_description":"A required parameter

I’t san omniauth error and appears to be related [potentially] to this: No longer works with oauth2 gem v2.0+ · Issue #68 · decioferreira/omniauth-linkedin-oauth2 · GitHub

Help is appreciated!

I’m receiving the following errors:


(oidc) Authentication failure! openid_connect_discovery_error: OmniAuth::OpenIDConnect::DiscoveryError, Discovery document is missing

OIDC Log: Fetching discovery document raised error Faraday::ConnectionFailed FinalDestination: lookup failed

I have my plugin setting “openid connect discovery document” set in the Admin Settings as: https://<auth_provider>/.well-known/openid-configuration and I can successfully hit it in the App Docker container that is running with a Curl command and even in the Rails console.

Any idea why I’m receiving these errors? Can’t integrate properly because of this. Also, I’m behind the intranet and using a company proxy if that is any help. Like i said, with the proxy eneabled in the ENV of the container, i can properly hit the “openid connect discovery document” url.

2 posts were split to a new topic: Allowing multiple OIDC sources

A post was split to a new topic: Overriding avatars with OIDC

Hello!

New question: does this plugin handle session management? (Final: OpenID Connect Session Management 1.0).
I don’t think so because even if the OP send the session_state data, I see nowhere in the code where it is stored as a cookie or so.

So this is a question/feature request :slight_smile: It would be terrific!

1 Like

When using this plugin with AWS Cognito, to logout, Cognito requires passing a client_id parameter to the logout URL. As best as I can tell, there is no way to add additional query parameters to the logout URL - is that right? If not, is it possible to add this capability?

Hey Folks :wave:t3:

I have written a tiny extension to this plugin (technically in the form of a theme/component) - to hide the button “Login via OIDC” in the login popup, but initiate the login-via-oidc flow by accessing a special URL.

discourse-autooidc.zip (1,0 KB)

Use case for this feature is to provide a secure and conveniant (automatic) login via oauth to the members of our company, without exposing a public link to the OAuth-Provider (Authentik in our case, but should also work with Authelia, Keycloak, Auth0, Okta,
) and without annoying all other users with an login-via-oidc-button they never can or should use.

To login via OIDC, just call https://<your-discourse-base-url>/login#autooidc

2 Likes

You may be interested in GitHub - discourse/discourse-hide-auth-method: A theme component which allows hiding a specific login method from the UI, without fully disabling it, which does something similar

2 Likes

Keycloak supports Backchannel logout URL:

URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). If omitted, no logout request will be sent to the client is this case.

It would be great, if this plugin exposes some endpoint, which accepts payload from Keycloak and logouts immediately some user from all sessions. Otherwise, when we disable user in Keycloak, we must wait maximum session age (which is pretty big by-default)

You could also log them out of all sessions using the user’s admin page (e.g. /admin/-1/system) and click the Log Out button at the top of the page.

Hello,

When the discovery document fetching fails (for example when there’s a timeout), the plugin caches the error which means authentication is unavailable for 10 minutes. Is it possible not to cache the error so that fetching is retried sooner?

Regards

Sorry fo the ping, but there is an open PR for this which should be trivial to merge to add PKCE support.

@nbianca I saw you being the latest committer to the repo, could you have a look, maybe? :pray:

1 Like