概要
Discourse グループのオーナーである非管理者ユーザーは、Web UI の招待ダイアログを通じて、そのグループが割り当てられた状態で新規メンバーを正常に招待できます。REST API(/invites.json、グローバルスコープの API キー、正しい Api-Username)を使用した同一の操作は、ペイロードに group_names/group_ids が含まれている場合のみ、403 invalid_access を返します。重要な点として、ユーザーにモデレーター権限を付与しても API 呼び出しは修正されず、フルの管理者権限を付与した場合のみ成功します。これは、モデレーター権限が他のすべてのテストシナリオ(Web UI、グループ指定なしの API 招待)では十分であるにもかかわらずです。
環境
- Discourse バージョン: 2026.7.1
- API キーの種類: グローバルスコープ、CheriArchives = テストユーザーの正確なユーザー名
再現手順
- 非管理者かつ非モデレーターのユーザー(
<userid>)を作成し、グループ<group_name>のオーナーにします。 - Web UI で
<userid>として操作: グループなしで招待 → 成功。<group_name>が割り当てられた状態で招待 → 成功。 - API で
<userid>として操作(グローバルスコープのキー、Api-Username=<userid>):group_namesなしのPOST /invites.json→ 成功。group_names=<group_name>(自身がオーナーのグループ)を含むPOST /invites.json→ 403invalid_access。
<userid>をモデレーターに昇格。手順 3 のグループ指定 API 呼び出しを繰り返す → 依然として 403invalid_access。<userid>を管理者に昇格。手順 3 のグループ指定 API 呼び出しを、同じキー、同じペイロードで繰り返す → 成功。
期待される動作
グループのオーナー権限のみで、非スタッフユーザーが Web UI 経由で招待時にそのグループを割り当てられる十分な権限であるため、Api-Username を介して同じユーザーとして認証された API も、同じ権限を尊重すべきです。少なくとも、モデレーター(スタッフである)はここでは非特権ユーザーと同様に動作すべきではありません。モデレーターがロールなしの場合と同一に失敗し、管理者のみが成功するという事実は、API のコードパスがグループのオーナー権限や一般的なスタッフステータス(モデレーターに対しては真となる user.staff?)ではなく、特に user.admin? をチェックしていることを示唆しています。
実際の動作
API は、操作するユーザーがフルの管理者でない限り、グループ指定の招待に対して常に 403 を返します。グループのオーナー権限(Web UI 経由で動作確認済み)およびモデレーター/スタッフステータス(直接昇格テストで確認済み)は、いずれも Web UI 経由またはグループ指定なしの API ケースでは十分であるにもかかわらず、API パスでは不十分です。
Discourse チームへの質問
API 認証によるグループ指定招待のコードパスは、Web UI / セッション認証パスがグループのオーナー権限や user.staff? をチェックするように、それらをチェックするのではなく、明示的に user.admin? を要求しているのでしょうか?もしそうであれば、これは意図的なもの(文書化されていない API 固有の制限)でしょうか、それともこのアクションに対して API のガーディアンチェックが Web のガーディアンチェックから乖離しているバグでしょうか?
必要であれば、完全なリクエスト/レスポンスログ(キーは伏せ字)を提供できます。