Discourse OAuth2 の基礎

:discourse2: | 概要 | Discourse OAuth2 Basic は、ユーザー詳細をトークンで取得できる JSON API エンドポイントを持つと仮定した、基本的な OAuth2 プロバイダーをサポートします。
:open_book: | インストールガイド | このプラグインは Discourse コアにバンドルされています。プラグインを個別にインストールする必要はありません。

機能

このプラグインを使用すると、基本的な OAuth2 プロバイダーを Discourse の認証として利用できます。多くのプロバイダーで動作するはずですが、ログインしているユーザーに関する情報を取得するための JSON エンドポイントを提供している必要があります。

これは主に、あまり人気のないログインプロバイダーを使用している人にとって役立ちます。Google、Facebook、Twitter を使用したい場合は、それらは最初から含まれているため、このプラグインは不要です。また、Github リポジトリで他のログインプロバイダーを探すこともできます。

設定

基本設定

  1. まず、OAuth2 プロバイダーで Discourse アプリケーションを登録します。リダイレクト URI が必要になります。

    http://DISCOURSE_HOST/auth/oauth2_basic/callback

:information_source: DISCOURSE_HOST を適切な値に置き換え、有効になっている場合は https を使用していることを確認してください。OAuth2 プロバイダーから client IDsecret、およびいくつかの URL が提供されます。

  1. 管理設定OAuth2 ログイン に移動し、OAuth2 プロバイダーの基本設定を入力します。
  • oauth2_enabled - 機能を有効にするためにチェックを入れます
  • oauth2_client_id - プロバイダーからのクライアント ID
  • oauth2_client_secret - プロバイダーからのクライアントシークレット
  • oauth2_authorize_url - プロバイダーの承認 URL
  • oauth2_token_url - プロバイダーのトークン URL

:information_source: 上記の設定値がわからない場合は、プロバイダーの開発者ドキュメントを確認するか、カスタマーサポートに連絡してください。

JSON ユーザーエンドポイントの設定

Discourse は、OAuth2 プロバイダーから承認トークンを受け取ることができるようになりました。ただし、認証を完了するためには、Discourse がさらに多くの情報を必要とします。

トークンに基づいてユーザー情報を取得できる API エンドポイントが必要です。

例えば、OAuth2 プロバイダーの SoundCloud はそのような URL を提供しています。SoundCloud の OAuth2 トークンを持っている場合、https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN に GET リクエストを送信すると、ユーザー情報が含まれた JSON オブジェクトが返されます。

Discourse でこれを設定するには、oauth2_user_json_url 設定の値を設定する必要があります。この場合、以下の値を入力します。

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

:token の部分は、認証完了時に受け取った承認トークンに置き換える必要があることを Discourse に伝えます。

最後のステップを完了する必要があります。Discourse に、受け取った JSON で利用可能な属性を知らせる必要があります。以下は 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"
}

oauth2_json_user_id_pathoauth2_json_username_pathoauth2_json_name_pathoauth2_json_email_path 変数を、JSON の適切な属性を指すように設定する必要があります。

必須の属性は id のみです。将来ユーザーがログインした際に正しいアカウントを取得するために必要です。他の属性は利用可能であれば非常に役立ちます。これらにより、ユーザーのサインアッププロセスが高速化され、フォームに事前に入力されるためです。

以下は、JSON パス設定を構成した方法です。

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

permalink を使用したのは、JSON 内の username よりも Discourse が期待するユーザー名に近いように思えたためです。メールパスを省略したことに注意してください。SoundCloud はメールを提供しないため、ユーザーは Discourse で初めてサインアップする際にメールを提供して確認する必要があります。

JSON オブジェクトから必要なプロパティがネストされている場合は、ピリオドを使用できます。例えば、API が以下のような異なる構造を返した場合。

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

oauth2_json_user_id_pathuser.idoauth2_json_email_pathuser.email.address を使用できます。

キー自体にピリオドが含まれている場合は、ダブルクォートで囲むか、バックスラッシュでピリオドをエスケープする必要があります。例えば、以下の JSON が与えられた場合。

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

パスを example\.com/uid または "example.com/uid" として指定します。

グループとユーザーフィールドの同期

  • oauth2_json_groups_path: ユーザーのグループを文字列の配列として含む JSON パス。最初のメンバーがログインした後、これらのグループは Discourse のグループ設定の「関連するグループ」セクションで選択可能になります。グループ同期を無効にする場合は空白のままにしてください。

  • oauth2_user_field_mappings: Discourse のユーザーフィールドに保存される JSON パスのマッピング。ユーザーフィールドは数値 ID で識別され、管理パネルから編集する際の URL で確認できます。

:warning: oauth2_json_email_path を設定した場合、OAuth2 プロバイダーは そのユーザーがそのメールアドレスを所有していることを確認する必要がありますこれを行わないと、Discourse でのアカウント乗っ取りにつながる可能性があります!

:discourse2: 当方でホストされていますか?このプラグインは、ビジネスプランおよびエンタープライズプランで利用可能です。OAuth 2.0 & OpenID Connect Support | Discourse - Civilized Discussion

:spiral_notepad: ユーザーのサインアップを自動化する必要がありますか?Auto-provisioning user accounts when SSO is enabled をご覧ください。

「いいね!」 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
Auto-provisioning user accounts when SSO is enabled
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin
SSO with TownNews CMS
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)
Error during SSO integration - Wholistic Minds
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 and Auth0
Migrate a Jive Clearspace forum to Discourse

こんにちは。
アプリケーションで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サーバーと、認可コードフローで設定しようとしています。

ユーザーが「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

ホスト名 discourse-app
プロセスID 653
アプリケーションバージョン 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 *****
時間 午後10時25分
パラメータ
コード def50200babf84f7376f99fefa34369d876566b6bc0a341d8fba431999a72549ac06f6aad01df6fa43061707c525ba5d725ad
状態 20139e0a134a5972566d4ddb9e5216973a

私の理解では、IPアドレスに問題があるということでしょうか?現在、Oauth2サーバーは私の開発環境(localhost)でホストされており、認可およびトークンエンドポイントはそれに応じて設定されています。これは問題でしょうか?

問題が見つかりました。

  1. 何らかの理由で /token エンドポイントが呼び出されていませんでした。OAuth に関連する管理者パラメータのオプションを最大まで設定した後、エンドポイントは応答なしで呼び出されました。
  2. /token エンドポイントを呼び出すのは webclient ではなく 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 を渡したところ、テストプロパティにパーミッションを渡すと、配列は既にRubyの配列として解析されていました。残念ながら、フィールドは配列要素を呼び出すためのRuby構文を拒否し、JavaScript構文を使用しようとすると TypeError String to Integer が発生しました。幸いにもRubyには上記の構文がありましたが、これが意図された方法でしょうか?

Authentik OAuth2 でこれを機能させることができましたが、oauth2 user json url 設定でいくつかの問題が発生しました。Authentik の user_info エンドポイント (/application/o/userinfo/) を使用しましたが、フィールドのマッピング方法がわかりませんでした。Authentik の OAuth2 で Discourse をセットアップする方法を探している人のために、概要は次のとおりです。

  • User id path: preferred_username
  • Username path: preferred_username
  • Name path: name
  • Email path: email
  • Email verified path: 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 emailauth overrides usernameauth overrides name の設定を使用して、それらを将来のログインに適用できます。残念ながら、アバターに同様の設定はありませんが、pr-welcome です。

「いいね!」 2

ありがとうございます!後でこれらを見つけました。リポジトリをフォークして、Robloxで機能するように独自のバージョンを追加しました。これにはアバターのオーバーライドも含まれていました。これはDiscourseConnectのアバターオーバーライドを使用しているだけで、人々はそれを変更できないと信じています。

ただ、RobloxはOAuthでメールを提供していないので、残念ながらメールでサインアップしてもらう必要があります。しかし、それは皆さんにとっては問題ではありませんね(笑)。

投稿が新しいトピックに分割されました:Twitterログインがメタで機能しない

これはまだ機能するかどうか、誰か知っていますか?

はい。このプラグインは動作すると確信しています。:+1:

「いいね!」 1

こんにちは。このプラグインを discourse discuss.frontendlead.com に統合できました。Teachable OAuth を使用しています: https://docs.teachable.com/docs/oauth-quickstart-guide

ただし、Teachable で現在有料アカウントを持っている場合にのみ、正常に登録できるようにしたいと考えています。この処理を行うには、プラグインにカスタム機能を追加する必要があるかと思います。設定に、OAuth 後に開発者が特定の操作を実行できるカスタムコードという別のフィールドを導入することは可能でしょうか?あるいは、他に良い提案があれば教えてください。

編集: リポジトリをフォークして、ここで動作させることができました:

Teachable を使用していて同様のことを試みている他の人がいれば、私のリポジトリはそのまま動作します。唯一の違いは、コースを購入していない場合、私のドメインにアクセスして購入する必要があるというメッセージが表示されることです。これは、ご自身のユースケースに合わせて更新する必要があるかもしれません。

「いいね!」 2

それは素晴らしいですね!

Discourse PatreonプラグインのOAuth2登録にも同様の状況があります。「Patreonでログイン」が有効になっている場合、Patreonアカウントを持つ誰もがDiscourseサイトに登録できます。サイト所有者が一般的に望むのは、_自分の_サポーターのみがDiscourseアカウントを登録できるようにすることです。Patreon認証に同様のロジックを追加できるように、Patreonから詳細情報が返されるのでしょうか?

「いいね!」 1

@qlands さんと同じエラーが発生しています。

当初は、プロファイル情報をトークンに含めて送信する予定でした。それが機能しなかったので、JSONアプローチを試すためにインデントを削除しましたが、JSONファイルを呼び出すところまで到達しません。

エラーメッセージは次のとおりです。

(oauth2_basic) 認証失敗! invalid_credentials: OAuth2::Error, {
  "access_token":"fa79b6fe0763862f5a8fd8",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"profile"
}

上記の返信で何か問題が見られますか?
OAuth2サーバーがトークンを200で返したのに、なぜプラグインがinvalid_credentialsエラーを生成するのでしょうか?