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 Admin → Settings → OAuth2 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"

Group & User Field Sync

  • oauth2_json_groups_path: JSON path which contains the user’s groups as an array of strings. After the first member has logged in, these groups will be available for selection in the ‘associated groups’ section of the Discourse group settings. Leave blank to disable group syncing.

  • oauth2_user_field_mappings: mappings of JSON paths which will be stored in Discourse User Fields. User fields are identified by their numeric ID, which can be found in the URL when editing them via the admin panel.

: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

:spiral_notepad: Need to automate user sign-ups? See Auto-provisioning user accounts when SSO is enabled

Last edited by @david 2026-05-28T11:12:59Z

Check documentPerform check on document:
28개의 좋아요
Keycloak with Discourse
Discourse SSO with OAuth2
Login from another user database
Shopify Integration
Auto-provisioning user accounts when SSO is enabled
OAuth2 integration with Drupal
How can we enable Auth0 SSO in Discourse
Is "partial" SSO possible?
How to force users link phone number when they using Discourse?
How to login to discourse from external website
OAuth connection of discourse
Login flow (Flask -> Discourse -> Flask) with OAuth
How to use Oauth2 service provided by discourse?
OAuth2 Custom Redirects Plugin
Set up Salesforce auth using OAuth2 basic support plugin
Login on discourse using mastodon credentials
Open source will support customized provider SSO
Oauth2 with fusionauth cert issues
Custom Login / Registration from another API
Migrate a Jive Clearspace forum to Discourse
CodeBerg support
SSO and Auth0
Intergrate Discourse with keycloak
Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso)
Drupal 8 and Discourse shared SSO
Suggestion for improving Integrated Authentication development
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?
Discourse for self hosting
Gate our community to just members of our Shopify site?
Discourse + Intercom (Current User Id)
Integration into custom auth system where emails are not unique?
Twitter login doesn't work on meta
ADFS Authentication
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
SSO with TownNews CMS
Shopify Integration
Pulling user auth0 sub from OAuth2.0 plugin
[Admin-Hinweis] Eines deiner Themes oder Plug-ins enthält Code, der aktualisiert werden muss
Error during SSO integration - Wholistic Minds
Allowing multiple OIDC sources
[Admin-Hinweis] Eines deiner Themes oder Plug-ins enthält Code, der aktualisiert werden muss
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
Populating email field on login page
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin

안녕하세요,

OAuth2 Basic를 사용하여 Discourse를 우리 애플리케이션에 통합하려고 시도하고 있지만, 로그에 다음 오류가 발생하고 있습니다:
참고: 현재 연결을 디버깅하기 위해 NGROK를 사용 중입니다.

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}

“oauth2 callback user id path” 및 “oauth2 callback user info paths” 파라미터는 비워 두었습니다.

도움이 될 만한 아이디어가 있다면 알려주시면 감사하겠습니다.

이것을 Microsoft의 XBL 서비스 인증에 사용할 수 있나요?

논리는 이 것과 유사할 것 같습니다.

안녕하세요 여러분. 내부 Oauth2 서버와 authorization code flow를 사용하여 이 플러그인을 설정하려고 시도하고 있습니다.

사용자가 "Oauth 연결"을 클릭하면 /authorize 엔드포인트가 작동하고 코드가 콜백으로 반환됩니다. 하지만 그 후 Discourse에서 일반적인 500 오류인 "Oops. The software powering this discussion forum encountered an unexpected problem"이 표시되고 /token 엔드포인트에는 접근되지 않습니다.

에러 로그는 다음과 같이 표시됩니다:
OAuth2::ConnectionError (FinalDestination: all resolved IPs were disallowed) 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 서버에서 /profile JSON 응답의 한 필드에 오타가 있었습니다. 오타를 수정한 후에는 모든 것이 정상적으로 작동했습니다.
하지만 말씀드리고 싶은 것은, Discourse 로그가 매우 오해의 소지가 있을 수 있다는 점입니다. 콜백에는 아무 문제가 없었습니다.

팀 여러분,

인가 응답에서 사용자 JSON 요청에 필요한 ID를 가져오는 데 문제가 있습니다. 문서를 살펴본 결과, 계정 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"]
      }
   ]
}

oauth2 콜백 사용자 ID 경로를 permissions[0].accountId로 설정해 보았지만, uid 값이 항상 비어 있습니다. 안타깝게도 사용자 JSON을 가져오기 위한 호출에는 JSON URL에 이 accountId가 필요합니다.

permissions.first.accountId를 전달하여 이 문제를 해결할 수 있었습니다. permissions를 테스트 속성에 전달하면 배열이 이미 Ruby 배열로 파싱되어 있다는 것을 발견했습니다. 불행히도 필드는 배열 요소를 호출하는 Ruby 구문을 거부하는 것 같고, JavaScript 구법을 사용하려고 하면 TypeError String to Integer가 발생합니다. 다행히 Ruby에는 위의 구문이 있었는데, 이것이 의도된 방법인가요?

Authentik OAuth2와 함께 이 문제를 해결했습니다. 다만 oauth2 user json url 설정에서 몇 가지 문제가 있었습니다. 해당 설정에 Authentik의 user_info 엔드포인트(/application/o/userinfo/)를 사용했지만, 필드를 어떻게 매핑해야 할지 몰랐습니다. Discourse를 Authentik의 OAuth2와 함께 설정하는 방법을 찾고 계신 분들을 위해 요약하면 다음과 같습니다:

  • User id 경로: preferred_username
  • Username 경로: preferred_username
  • Name 경로: name
  • Email 경로: email
  • Email verified 경로: email_verified
  • Avatar: 비어 있음.

다음과 같은 문제들이 있었습니다:

  1. 처음에 json url https://DOMAIN/application/o/userinfo/에서 끝나는 슬래시를 누락했습니다. 이로 인해 사용자 정보 요청(소스 영구 링크)가 301 HTTP 코드를 반환하여 로그인이 실패했습니다. 규격상 끝나는 슬래시가 있어야 하는지는 알 수 없지만, 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

디버그 로그를 보면 JSON 응답에 picture 요소가 설정되어 있는 것을 확인할 수 있지만, 신규 사용자나 기존 사용자를 가리지 않고 사용자의 아바타가 변경되지 않습니다.

무엇을 놓치고 있는 걸까요?

로그인 버튼의 아이콘을 다른 아이콘이나 이미지로 교체하는 가장 좋은 방법은 무엇인가요?

.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 설정을 사용하면 향후 로그인 시 해당 항목이 적용됩니다. 아바타에 대해서는 현재 유사한 설정이 없지만, pr-welcome 입니다.

2개의 좋아요

감사합니다! 사실 나중에 이 내용을 찾았습니다. 저장소를 포크하고, 로블록(Roblox)에서 이 기능이 작동하도록 제 버전을 추가했습니다. 여기에는 아바타 오버라이드도 포함되었는데, 제 생각에는 이는 DiscourseConnect의 아바타 오버라이드를 사용하여 사용자가 아바타를 변경하지 못하게 하는 방식인 것 같습니다.

다만, 로블록이 OAuth를 통해 이메일 주소를 제공하지 않아서 아쉽습니다. 그래서 사용자에게 이메일로 가입하도록 해야 하는 상황입니다. 하지만 여러분에게는 큰 문제가 아닐 테니 걱정 마세요, 하하.

게시물이 새 주제로 분리되었습니다: Twitter 로그인 메타에서 작동하지 않음

이것이 여전히 작동하는지 아시는 분 계신가요?

네. 이 플러그인이 작동하는 데 확신이 있습니다. :+1:

1개의 좋아요

안녕하세요, discourse discuss.frontendlead.com에 이 플러그인을 통합했습니다. 현재 Teachable OAuth를 사용 중입니다: OAuth Quickstart Guide

다만, Teachable에서 현재 유료 계정이 있는 사용자만 성공적으로 등록할 수 있도록 제한하고 싶습니다. 이를 처리하기 위해 플러그인에 사용자 정의 기능을 추가해야 할 것 같습니다. OAuth 인증 후 특정 작업을 수행할 수 있도록 설정에 'OAuth 후 사용자 정의 코드’라는 필드를 추가할 수 있을까요? 개발자가 가입 후 특정 작업을 실행할 수 있게 하는 것이죠. 더 나은 제안이 있다면 알려주세요.

수정: 저장소를 포크하여 여기서 작동하도록 만들었습니다:

Teachable을 사용하면서 동일한 작업을 시도하는 다른 사람이 있다면, 제 저장소를 그대로 사용하면 됩니다. 다만, 코스를 구매하지 않은 경우 제 도메인에서 구매해야 한다는 메시지가 표시됩니다. 본인의 사용 사례에 맞게 이 부분을 수정하는 것이 좋습니다.

2개의 좋아요

훌륭하네요!

Discourse Patreon 플러그인에서 OAuth2 등록 시에도 비슷한 상황이 있습니다. "Patreon으로 로그인"이 활성화되면 Patreon 계정이 있는 누구나 Discourse 사이트에 등록할 수 있습니다. 사이트 소유자들이 일반적으로 원하는 것은 자신의 후원자만 Discourse 계정을 등록할 수 있도록 하는 것입니다. 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"
} 

위 응답에 잘못된 부분이 있는지 확인해 주시겠습니까?
왜 OAuth2 서버가 200 상태 코드와 함께 토큰을 반환했는데도 플러그인은 invalid_credentials 오류를 생성하는 것일까요?