Discourse OAuth2 Basic

:discourse2: Summary Discourse OAuth2 Basic supports basic OAuth2 providers, assuming they have a JSON API endpoint where user details can be retrieved by token.
:open_book: Install Guide This plugin is bundled with Discourse core. There is no need to install the plugin separately.

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 AdminSettingsOAuth2 Login 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!

: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 @tobiaseigen 2025-07-16T21:39:12Z

Check documentPerform check on document:
28 лайков
Keycloak with Discourse
Discourse SSO with OAuth2
Login from another user database
Shopify Integration
How can we enable Auth0 SSO in Discourse
OAuth2 integration with Drupal
OAuth connection of discourse
Login flow (Flask -> Discourse -> Flask) with OAuth
How to use Oauth2 service provided by discourse?
How to login to discourse from external website
Is "partial" SSO possible?
Set up Salesforce auth using OAuth2 basic support plugin
How to force users link phone number when they using Discourse?
OAuth2 Custom Redirects Plugin
Custom Login / Registration from another API
Login on discourse using mastodon credentials
Open source will support customized provider SSO
Oauth2 with fusionauth cert issues
Migrate a Jive Clearspace forum to Discourse
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin
Error during SSO integration - Wholistic Minds
What is supposed to go in “DISCOURSE_HOST”?
Custom Provider log-in with OAuth only sign-up/log-in
Discord, Google and Microsoft login, is oAuth2 enough?
Populating email field on login page
CodeBerg support
Gate our community to just members of our Shopify site?
Intergrate Discourse with keycloak
Integration into custom auth system where emails are not unique?
Twitter login doesn't work on meta
Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso)
Question about Docker Manager?
Discourse OpenID Connect (OIDC)
🧩 How to Build an Android App User Community with Discourse? [HeyApks Project]
Bundling more popular plugins with Discourse core
Drupal 8 and Discourse shared SSO
Discourse for self hosting
Discourse + Intercom (Current User Id)
Auto-provisioning user accounts when SSO is enabled
ADFS Authentication
Pulling user auth0 sub from OAuth2.0 plugin
Suggestion for improving Integrated Authentication development
Github and Twitter Login/Sign-Up Functionality?
Automatically creating a user when logging in with Webflow/Memberspace
Switching out authentication for a passwordless alternative
Removing Yahoo login from Core, and deprecating OpenID 2.0
Shopify Integration
SSO with TownNews CMS
SSO and Auth0

Здравствуйте,
Мы пытаемся интегрировать Discourse с нашим приложением, используя OAuth2 Basic, но в логах возникает следующая ошибка:
Примечание: Мы используем NGROK для отладки соединения.

Отладка OAuth2: запрос POST https://formshare.ngrok.io/oauth2/token

Заголовки: {"User-Agent"=>"Faraday v1.9.3", "Content-Type"=>"application/x-www-form-urlencoded", "Authorization"=>"Basic S2k2SFZtTVpuSTFHUExiRXVlWVJDNENiOkNvb1k0anlQemt3dWNRV21Sa2FWOVNnbHZLbjJFT3cxc3BIMmtMck9yY21vNDM4Tg=="}

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

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

Отладка OAuth2: статус ответа 200

От POST https://formshare.ngrok.io/oauth2/token

Заголовки: {"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"}

Тело: {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

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

(oauth2_basic) Ошибка аутентификации! invalid_credentials: OAuth2::Error, {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

Мы оставили параметры «путь к ID пользователя в обратном вызове OAuth2» и «пути к информации о пользователе в обратном вызове OAuth2» пустыми.

Будем благодарны за любые предложения.

Могу ли я использовать это для аутентификации в службе XBL от Microsoft?

Предполагаю, что логика будет аналогична этой?

Всем привет. Я пытаюсь настроить этот плагин с нашим внутренним сервером OAuth2, используя поток с кодом авторизации.

Когда пользователь нажимает «Подключиться через OAuth», эндпоинт /authorize работает, и код возвращается в обратный вызов. Однако затем Discourse показывает общую ошибку 500: «Ой. Программное обеспечение, управляющее этим форумом, столкнулось с неожиданной проблемой», и эндпоинт /token не вызывается.

В логе ошибок указано следующее:
OAuth2::ConnectionError (FinalDestination: все разрешенные IP-адреса были запрещены) lib/final_destination/ssrf_detector.rb:74:in lookup_and_filter_ips' lib/final_destination/http.rb:13:in connect’ lib/midd

hostname discourse-app
process_id 653
application_version 702f27e6ee10ac257f5fee3f331d05f5fa5d7a45
HTTP_HOST *****
REQUEST_METHOD GET
HTTP_USER_AGENT Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
HTTP_REFERER *****
HTTP_X_FORWARDED_FOR *****
HTTP_X_REAL_IP *****
time 10:25 pm
params
code def50200babf84f7376f99fefa34369d876566b6bc0a341d8fba431999a72549ac06f6aad01df6fa43061707c525ba5d725ad
state 20139e0a134a5972566d4ddb6f7f9092a2cddb9e5216973a

Как я понимаю, проблема связана с каким-то IP-адресом? В данный момент сервер OAuth2 работает в моей среде разработки (localhost), и эндпоинты authorize и token настроены соответствующим образом. Является ли это проблемой?

Нашел проблему:

  1. По какой-то причине конечная точка /token никогда не вызывалась. После заполнения максимального количества параметров в админ-панели, связанных с OAuth, конечная точка вызывалась без ответа.
  2. Я забыл, что конечную точку /token должен вызывать сервер Discourse, а не веб-клиент. Следовательно, сервер не мог обратиться к моему локальному серверу OAuth2. Размещение нашего сервера OAuth2 за доменом решило проблему.

Теперь я могу подключать существующих пользователей, но не понимаю, как регистрировать новых пользователей через этот плагин.
Если пользователь входит через OAuth, появляется ошибка о том, что у него нет активной учетной записи на сервере Discourse. Это нормально, так как это новый пользователь.

Существует ли отдельный обратный вызов для регистрации пользователя вместо входа? Или есть специальный параметр, который нужно установить для разрешения создания учетной записи?

OAuth-сервер моей компании возвращал JSON-ответ по адресу /profile с небольшой опечаткой в одном из полей. После исправления опечатки всё заработало корректно.
Однако хочу отметить, что логи Discourse могут вводить в заблуждение! С самим колбэком всё было в порядке.

Привет, команда,

У меня возникла проблема с извлечением ID, необходимого для моего JSON-запроса пользователя, из ответа авторизации. Согласно документации, ID аккаунта передается в вложенном массиве:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"Bearer",
   "expires_in":1800,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
   "permissions":[
      {
        "accountId":123,
        "availableScopes":["contacts_view", "contacts_me", 
"contacts_edit", "finances_view", "events_view"]
      }
   ]
}

Я пробовал установить путь к ID пользователя в обратном вызове OAuth2 как permissions[0].accountId, но значение uid всегда остается пустым. К сожалению, для вызовов получения JSON пользователя требуется этот accountId в URL запроса.

Мне удалось заставить это работать, передав permissions.first.accountId. Я обнаружил, что при передаче permissions в тестовое свойство массив уже был распарсен как массив Ruby. К сожалению, поля, похоже, отвергают синтаксис Ruby для обращения к элементам массива, и любая попытка использовать синтаксис JavaScript приводила к ошибке TypeError: String to Integer. К счастью, в Ruby есть синтаксис, приведенный выше. Является ли это предполагаемым методом?

У меня наконец получилось настроить интеграцию с Authentik OAuth2, однако возникли некоторые сложности с настройкой oauth2 user json url. Я использовал эндпоинт user_info Authentik (/application/o/userinfo/), но не знал, как сопоставить поля. Для тех, кто ищет информацию о настройке Discourse с OAuth2 от Authentik, вот краткое резюме:

  • Путь к ID пользователя: preferred_username
  • Путь к имени пользователя: preferred_username
  • Путь к имени: name
  • Путь к электронной почте: email
  • Путь к подтверждению электронной почты: email_verified
  • Аватар: пусто.

У меня возникли следующие проблемы:

  1. Сначала я забыл добавить завершающий слэш в URL JSON https://DOMAIN/application/o/userinfo/. Из-за этого запрос информации о пользователе (ссылка на исходный код) возвращал HTTP-код 301, что приводило к сбою входа. Не знаю, обязателен ли завершающий слэш по спецификации, но, возможно, стоит правильно обрабатывать код 301.
  2. Отладка этого процесса оказалась непростой. Настройка oauth2 debug auth оказалась спасением, но… Logster обрезает отладочный лог до того, как выводит содержательные данные ответа. Мне пришлось вручную изменить строку лога в контейнере на:
    log("user_json_response: #{user_json_response.status} #{user_json_response.headers} #{user_json_response.body}")
    
    Возможно, эту строку лога стоит обновить? Думаю, это поможет другим пользователям разобраться с путями атрибутов JSON.
4 лайка

Я только что настроил Auth0 с помощью плагина и обнаружил, что аватары не подтягиваются.

Вот соответствующие настройки:

  DISCOURSE_OAUTH2_ENABLED: true
  DISCOURSE_OAUTH2_CLIENT_ID: '${DISCOURSE_OAUTH2_CLIENT_ID}'
  DISCOURSE_OAUTH2_CLIENT_SECRET: '${DISCOURSE_OAUTH2_CLIENT_SECRET}'
  DISCOURSE_OAUTH2_AUTHORIZE_URL: '${DISCOURSE_OAUTH2_ISSUER}/authorize?connection=xxx&login_options=yyy'
  DISCOURSE_OAUTH2_TOKEN_URL: '${DISCOURSE_OAUTH2_ISSUER}/oauth/token'
  DISCOURSE_OAUTH2_USER_JSON_URL: '${DISCOURSE_OAUTH2_ISSUER}/userinfo'
  DISCOURSE_OAUTH2_SCOPE: 'email openid profile'
  DISCOURSE_OAUTH2_JSON_USER_ID_PATH: 'sub'
  DISCOURSE_OAUTH2_JSON_USERNAME_PATH: 'nickname'
  DISCOURSE_OAUTH2_JSON_NAME_PATH: 'name'
  DISCOURSE_OAUTH2_JSON_EMAIL_PATH: 'email'
  DISCOURSE_OAUTH2_JSON_EMAIL_VERIFIED_PATH: 'email_verified'
  DISCOURSE_OAUTH2_JSON_AVATAR_PATH: 'picture'
  DISCOURSE_OAUTH2_EMAIL_VERIFIED: true
  DISCOURSE_OAUTH2_OVERRIDES_EMAIL: true
  DISCOURSE_OAUTH2_ALLOW_ASSOCIATION_CHANGE: false

В логах отладки я вижу, что элемент picture присутствует в JSON-ответе, но аватар пользователя не меняется ни для новых, ни для существующих пользователей.

Что я упустил?

Какой лучший способ заменить иконку на кнопке входа на другую иконку или изображение?

.btn-social.oauth2_basic:before {
    content: url('https://www.contoso.com/path/to/image');
}

.btn-social.oauth2_basic > svg {
    display: none;
}

Это выглядит достаточным, но немного хакичным.

2 лайка

Похоже, что плагин обновляет аватар/имя пользователя только при первоначальном создании аккаунта, а не при каждом входе в систему.

Есть ли способ исправить это, чтобы плагин обновлял аватар также при входе/переподключении?

Вы можете использовать настройки auth overrides email, auth overrides username и auth overrides name, чтобы эти изменения применялись при следующих входах в систему. К сожалению, у нас пока нет аналогичной настройки для аватаров, но мы будем рады соответствующему pull-запросу.

2 лайка

Спасибо! Я позже сам нашёл эти материалы. Я сделал форк репозитория и добавил свои версии, чтобы всё заработало с Roblox, включая переопределение аватаров. Насколько я понимаю, это использует переопределение аватара через DiscourseConnect, чтобы пользователи не могли его изменить.

Однако есть один момент: Roblox не предоставляет email через OAuth, поэтому, к сожалению, им приходится регистрироваться с указанием email. Но для вас это, думаю, не проблема, ха-ха.

Пост был разделён на новую тему: Вход в Twitter не работает на Meta

Кто-нибудь знает, работает ли это ещё?

Да. Я уверен, что этот плагин работает. :+1:

1 лайк

Привет, мне удалось интегрировать этот плагин в мой форум discuss.frontendlead.com. Я использую OAuth от Teachable: OAuth Quickstart Guide

Однако я хочу разрешить успешную регистрацию только тем пользователям, у которых есть активный платный аккаунт на Teachable. Думаю, мне нужно добавить в плагин пользовательский функционал для обработки этого. Подскажите, возможно ли добавить новое поле в настройки с названием «Пользовательский код после OAuth», которое позволит разработчикам выполнять определённые действия после регистрации? Или, если есть лучшие предложения, пожалуйста, дайте знать.

Редактирование: Я форкнул репозиторий и получил работающее решение здесь:

Если кто-то другой, кто использует Teachable, пытается сделать то же самое, мой репозиторий будет работать из коробки. Единственное, если вы не купили курс, система сообщит, что нужно перейти на мой домен для покупки. Возможно, вам стоит обновить это сообщение под свои нужды.

2 лайка

Это здорово!

Аналогичная ситуация возникает с регистрацией через OAuth2 в плагине Discourse Patreon. Когда включена опция «Войти через Patreon», зарегистрироваться на сайте Discourse может любой пользователь с аккаунтом Patreon. Обычно владельцы сайтов хотят разрешить регистрацию только своим сторонникам. Интересно, возвращает ли Patreon данные, которые позволили бы внедрить аналогичную логику в аутентификацию через Patreon?

1 лайк

У меня точно такая же ошибка, как у @qlands выше.

Мой первоначальный план заключался в том, чтобы отправлять информацию профиля в токене. Поскольку это не сработало, я упростил отступы, чтобы попробовать подход с JSON. Но дело даже не доходит до вызова JSON-файла.

Сообщение об ошибке:

(oauth2_basic) Authentication failure! invalid_credentials: OAuth2::Error, {
  "access_token":"fa79b6fe0763862f5a8fd8",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"profile"
} 

Вы видите что-то не так в вышеприведённом ответе?
Почему плагин выдаёт ошибку invalid_credentials, в то время как сервер OAuth2 ответил кодом 200 с токеном?