ユーザーAPIキーの仕様

Discourse には、非常に特定のプロトコルに従うことで、ユーザーごとに API キーを生成するシステムが含まれています。この機能により、モデレーターの介入を必要とせずに、「アプリケーション」が Discourse インスタンスにアクセスできます。

概要

大まかな流れは以下の通りです。

  1. クライアント(デスクトップアプリ、ブラウザプラグイン、モバイルアプリ)が秘密鍵/公開鍵ペアとリターン URL を生成します

  2. クライアントは Discourse のルートにリダイレクトし、Discourse に公開鍵を渡します

  3. Discourse はユーザーからアプリの使用許可を取得します

  4. Discourse がユーザー API キーを生成します

  5. Discourse は、ユーザー API キーを含む公開 API キーで暗号化されたペイロードをリターン URL にリダイレクトします

詳細

使用例:

  1. 最終ユーザーに代わって複数の Discourse サイトの通知数を取得するために、Discourse サイトをポーリングするデスクトップアプリケーション。

  2. 最終ユーザーに代わって Discourse サイトをポーリングし、プッシュ通知を処理するモバイルアプリケーション。

  3. 最終ユーザーに対して、様々な Discourse サイトに関するダッシュボードを提供する Web アプリケーション。

  4. 一般的な企業アプリの一部として Discourse を消費するサードパーティ製アプリとのカスタム統合。例:Discourse コミュニティの通知を Hopscotch アプリに統合する。

設計:

サイト設定

  • allow_user_api_key_scopes:ユーザー API キーに許可されるアクセススコープ。スコープはこちらで定義されています。利用可能な組み込みスコープは、readwritemessage_buspushone_time_passwordnotificationssession_infobookmarks_calendaruser_status です(プラグインは追加のスコープを登録できます)。

  • user_api_key_allowed_groups:ユーザー API キーの生成を許可されるグループを制御します(デフォルトは管理者、モデレーター、および trust_level_0)。

  • allowed_user_api_push_urls:プッシュ通知の送信先となることができるサイトのリスト

  • allowed_user_api_auth_redirects:ユーザー API キー生成後の許可されたリダイレクト先

グローバル設定

  • max_user_api_reqs_per_minute:50
  • max_user_api_reqs_per_day:4000

UX 要素

ユーザー API キーが付与されている場合、Discourse はユーザーページにアプリタブを表示します。

アプリタブには以下がリストされます。

  • アプリケーションの名前(例:「Discourse Notifier」)
  • 最終使用日
  • 承認日
  • 付与されたアクセススコープのリスト
  • キーを簡単に取り消せるアクセスを取り消すボタン

API キーの認証 UI

すべてのキーは、何が行われているかを明確に説明するページで、最終ユーザーによって明示的に承認される必要があります。例えば:

「Discourse Notifier」はあなたのアカウントに対して以下のアクセスを要求しています:

  • 通知の読み取りとクリア
  • ユーザーセッション情報の読み取り
  • ワンタイムログイントークンの作成

[承認]

API キーの生成フロー

API は、ユーザー側で単一の GET リクエストのみを必要とします。

https://sitename.com/user-api-key/new

:exclamation: Discourse 2.1 以降、これらのユーザー API キーは長期間使用されない場合、自動的に期限切れになります。サイト設定 revoke user api keys unused days はデフォルトで 180 に設定されています。

パラメータ:

  • auth_redirect:生成されたトークンと共にリダイレクトする URL
  • application_name:リクエストを行うアプリケーションの名前(ユーザーアカウントのアプリタブに表示されます)
  • client_id:クライアントの一意の識別子
  • nonce:クライアントが生成する一意の nonce。これは暗号化されたペイロード内で返されるため、クライアントはレスポンスの真正性を検証できます
  • scopes:キーに許可されるアクセススコープのカンマ区切りリスト。利用可能なスコープの全リストについては allow user api key scopes を参照
  • push_url:プッシュ通知を送信する URL(push または notifications がスコープに含まれている場合に必須かつ有効)
  • public_key:クライアントが生成した鍵ペアの公開鍵部分
  • padding(オプション):ペイロードの暗号化に使用する RSA パディングモード。受け入れられる値は pkcs1(デフォルト)または oaep です。新しいアプリケーションには OAEP を推奨します

/user-api-key/new が正しいパラメータで呼び出されると、2 つのことが起こり得ます。

  1. ユーザーがログインしていない場合、ログイン画面にリダイレクトされます(ログイン後、認証を再開します)
  2. ユーザーがログインすると、認証 UI が表示されます

認証が許可されると、システムは auth_redirect で定義された URL にリダイレクトし、生成されたユーザー API キー(key)、nonce、プッシュステータス(push)、および API バージョン(api)を含む JSON オブジェクトを保持する暗号化された payload パラメータを含めます。one_time_password スコープが要求された場合、別の暗号化された oneTimePassword クエリパラメータも含まれます。追加のセキュリティのため、client_id は返されません。

API バージョンの確認

Discourse のユーザーキー API はバージョン管理されています。クライアントは、https://sitename.com/user-api-key/new に対して HEAD リクエストを行うことで、Discourse サイトの API バージョンを確認できます。レスポンスには、サイトの API のバージョン番号を含む Auth-Api-Version という名前のヘッダーが含まれます。

API の消費

クライアント API の消費は、現在の管理者 API と多少異なります。

クライアントは 2 つのヘッダーを指定できます。

User-Api-Key(必須):生成されたキー

および

User-Api-Client-Id(オプション):データベース内のこの api_key 用に保存されている ‘client id’ を更新するためにこれを供給します。

これらのヘッダーが指定されると、クライアントは通常通り API に対してリクエストを実行できます。

ワンタイムログインパスワードの生成

バージョン 4 以降、API には特別なスコープ、すなわち one_time_password スコープが含まれており、これによりクライアントはユーザー API キーを使用してワンタイムパスワードを生成できます。上記の手順に従って API キーを生成する際にクライアントがこのスコープを含めると、暗号化された oneTimePassword がクライアントへのリダイレクト内で別のクエリパラメータとして含まれます。

または、クライアントは以下のパラメータで /user-api-key/otp に対して GET リクエストを行うことができます。

  • auth_redirect
  • application_name
  • public_key
  • padding(オプション)

および User-Api-Key ヘッダー。

このリクエストは、Discourse 内の画面にリダイレクトし、ユーザーにアプリケーションがサイトにアクセスすることを許可するよう求めます。ユーザーが承認すると、サイトは auth_redirect で定義された URL にリダイレクトし、ワンタイムパスワードを含む暗号化された oneTimePassword パラメータを含めます。クライアントは https://sitename.com/session/otp/ONE-TIME-PASSWORD をリクエストすることで、このワンタイムパスワードを使用してサイトにログインできます。(ワンタイムパスワードの有効期限は 10 分です。)

API キーの取り消し

API キーを取り消すには、User-Api-Key ヘッダーを付けた POST リクエストをパラメータなしで /user-api-key/revoke に行います。


最終レビュー:@SaraDev 2022-07-13T00:00:00Z

「いいね!」 31
Generating User Api Keys with REST API
Discourse Login & Registeration
Discourse sso login using Rest API
Custom Push Notifications: allowed user api push urls
Beta testing the iOS mobile app
How can I get user details via the user api key?
Authorization from a desktop application (and base domain site)
Secure way of encrypting payload in Javascript for user authentification
Can non-admin user issue their own API key?
Automatic Login from iOS/Android app
Delegated authentication for Discourse Mobile app
Generating User Api Keys with REST API
Generating User Api Keys with REST API
API CORS Headers Incorrect
Get back Username with API Key?
Is there any documentation on the User/Mobile API?
Passing draft text into a new response
Discourse Hub "connect"
Generate User API Keys for testing
Consolidated API Requests in the thousands yet our site has no active API keys listed, is this a concern?
Having issue accessing the Discourse APIs from react app
Discourse REST API Documentation
Having issue accessing the Discourse APIs from react app
CORS error accessing API from javascript application
Does Discourse have support for PAT tokens?
API key creation
Access via Discourse API, key and/or user rejected
Feasibility of allowing a User Api Key client to register a valid auth_redirect
Implement discourse Apple login using API
Thousands of user api requests and invalidation
Are User API Keys Not Generated When Logging in via Login Link?
Confusion about API Authenticated User
Confusion about API Authenticated User
Generate User Api Key Without User Approval
How to use discourse api in react native?
"Api-Key" and "Api-Username" for try.discourse.org?
How can I allow users to like posts using RESTapi
Allow_user_api_key这个设置在哪开启
Dexo - A Native iOS Client for Discourse
Acess-Control-Allow-Headers CORS Error with API after updating discourse
CORS error accessing API from javascript application
Clip To Discourse Chrome Extension - now with User API capability!
Unable to create "Single User" level API key, always defaults to "All Users"
Discourse index
Clip To Discourse Chrome Extension - now with User API capability!
Authentication Protocol re: App Integration
Embed Discourse in a native app?
Request header field User-Api-Key is not allowed by Access-Control-Allow-Headers
Request header field User-Api-Key is not allowed by Access-Control-Allow-Headers
Request header field Content-Type is not allowed by Access-Control-Allow-Headers
Create apikey for user programmatically as admin
How to fix 'Cannot read property '_links' of undefined'
Allow API use by regular users, not just admins
The purpose of the 2 Discourse API systems
Bot writer's tip: Processing every post
Using Zapier without being admin
Per User API Keys Not Working
Acess-Control-Allow-Headers CORS Error with API after updating discourse
Work with discourse users on an SPA

There are places I’ve strongly considered writing a delayed post tool, so I can compose a bunch of “word of the day” type things to keep going while I’m on vacation. Doing it without proper API access and pretending to be a browser seems somewhat more complicated than on other forum software.

(Just as an example of another use case.)

That is a good example, but keep in mind, our default will be only to enable read tokens, not write ones. Site admins will have to opt to allow write tokens.

Completely agree that the _t cookie hacks are a huge problem.

「いいね!」 2

Does max_user_api_calls_per_key_day setting apply to admin-created keys at /admin/api?

「いいね!」 1

Nope only to user api keys, we can look at adding extra limits for standard Api keys, it is a good safeguard

「いいね!」 1

To be clear, this is not implemented yet, correct?

No, it’s there (for almost 2,5 years now) - Admin - Settings - User API.

「いいね!」 4

As of Discourse 2.1 these user api keys now auto-expire if left unused for long periods of time, correct @sam?

「いいね!」 2

Correct the site setting: expire user api keys days is set to 180 out of the box.

「いいね!」 2

Okay, but you have to have admin access to see that page yes? And as an admin, it seems I can only create 1 key, so can’t create many keys for different users. confused.

「いいね!」 1

What are you trying to accomplish? It’s not clear because there is this (user api keys) and regular API tokens (which is what I think you are after) that admins can create for multiple users, but you have to do that from the individual user’s page inside of the admin dashboard by clicking on the “generate” button on the “API Key” field.

「いいね!」 4

Thanks! Yes, “regular API tokens” for users is what i was after. I’m sure I’d seen that a million times, and never realized it was there. :heavy_check_mark:

「いいね!」 3

Hey everyone I’m not sure if this was resolved? I see that it’s possible to create an “All Users” and (per user) level API token as an admin, but I’m interested in giving a user the power to generate his/her own token. Has there been work done on this? It sounds like the original thread was getting at this idea, and then it was lost. Thanks!

Download the mobile App and then add a site, that uses the user api key system you have to follow a very strict workflow, no plans to expose arbitrary generation of keys in user prefs

「いいね!」 3

Thank you! I downloaded the app, and then realized that the sites I belong to don’t have this enabled (I’ve been testing on my local machine with the Dockerized discourse). Just to make sure we are talking about the same thing - I’m interested in generating tokens to use just a scoped subset of functions (and not global API keys to do all the things). Is this what you are talking about?

It seems like, given that there is an endpoint to generate tokens, it would be logical to provide this function (to users with a certain trust level, for example) from within the site. Otherwise, it would need to be the case that the site generates some external page (with a server to hide an admin token) to generate the keys for the user. Is it the case that 1. there is no internal generation of tokens for the user (and why not?) and 2. Nobody has created some external app (javascript, flask, anything really) to perform this action?

「いいね!」 1

Yes.

Possibly, conceptually

  1. This is tricky to consume cause you need to use custom HTTP headers (by design)

  2. It would be very hard to educate even TL3 users about what the point is of this thing.

I prefer not to ship UI for this in core, but maybe you should write a plugin for your specific use case?

Can you explain a bit more about the “why” here?

The design of the system centers around “I have an external dedicated program”, “this program knows how to follow Discourse protocol”, “It asks for token”

API keys (non user ones) are much easier to consume cause you just append them after the ?

「いいね!」 4

Can I pass the API key generated from the user page on this? I was trying to use that API key and seeing ‘You are not permitted to view the requested resource.’ error on /categories.json API request

みなさん、こんにちは

もし重複していたらすみませんが、手順が非常に整理されているにもかかわらず、理解するのに苦労しています。

私は https://forum.domain.com に Discourse をインストールしており、https://development.domain.com にサイトがあります。このサイトから Discourse インストールに対して呼び出しを行い、いくつかのデータを取得・設定する必要があります。

Postman からのすべてのリクエストは、Api-Username と Api-Key を使用して問題なく動作します。

しかし、JS を使用したクロスオリジンリクエストの場合、Discourse は Api-Username を許可しないため、このスレッドで説明されているフロー、つまり User-Api-Key と User-Api-Client-Id を使用する方向に進んでいます。

基本的に、以下のサンプルリクエストで使用されているパラメータ PUBLIC_KEY、NONCE、CLIENTID の説明と、それらをどこで取得できるかを知りたいです。

https://forum.domain.com/user-api-key/new?public_key=PUBLIC_KEY&nonce=NONCE&scopes=SCOPES&client_id=CLIENTID&application_name=DEVELOP&auth_redirect=XXX

最後に、このフローにより、https://development.domain.com から https://forum.domain.com へのシームレスな API リクエストを、認証なしで行うことができるでしょうか。

追記:フォーラムとリクエストが行われているサイトの間には SSO が設定されているため、ユーザーはログインした状態になります。

ご助言をよろしくお願いいたします。

ちょっと待って、これはユーザーごとの設定ですか?任意のユーザーがこれを実行できるようにしているのですか?

当社のサーバー API は現在、ヘッダーベースの認証をサポートしており、ユーザー API キーと同様に CORS と連携して動作します。スコープを制限し、エンドユーザーがキーを生成できるようにしたい場合は、ユーザー API キーを使用してください。管理者が生成する場合は、管理者用キーを使用します。

「いいね!」 2

各ユーザーに個別のキーが必要になるとは思いません……私が求めていることは、1 つの管理者キーで十分です。

Postman を通して API を消費することは問題なくできます。例えば、/notifications.json?username=alanmurphy への GET リクエストは、ヘッダーに api-key を含めるだけで問題なくデータを取得できます。

Discourse インストールのコンソールからそのリクエストをトリガーしても、問題なくデータが返ってきます。つまり:

var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});
xhr.open("GET", "https://**********.com/notifications.json?username=alanmurphy");
xhr.setRequestHeader("api-key", "d06ca53322d1fbaf383a6394d6c229e56871342d2cad953a0fe26c19df7645ba");
xhr.setRequestHeader("api-userame", "system");
xhr.send();

すべて問題なし:+1:

ただし、Discourse に接続しようとしているサブドメインからこれを実行すると、CORS ポリシーによってブロックされたと表示されます。リクエストヘッダーフィールド api-keyAccess-Control-Allow-Headers で許可されていません。

許可されているヘッダーは以下の通りです:

Content-Type, Cache-Control, X-Requested-With, X-CSRF-Token, Discourse-Visible, User-Api-Key, User-Api-Client-Id

クロスオリジンリクエストに渡すべき認証パラメータと、それらをどこから取得できるかについてご教示いただければ大変助かります。

追伸:私の Discourse はドメインからのクロスオリジンリクエストを許可するように設定されていますので、これは完全にヘッダーの問題だと考えています。

ありがとうございます

「いいね!」 1