認証プロトコル:アプリ統合について

Hey all! My team and I have been looking into possible ways to integrate our [future] Discourse instance into our mobile application - Noom. Our iOS app is written in Objective-C with some Swift, and our Android application is written in Java with some Kotlin. We’ve been debating between full integration via API or web view as our goal is an SSO flow where our users can seamlessly transition from an in-app experience to our Discourse instance.

I’m currently waiting on our QA team to get back to me on which authentication protocols we currently use, but I was curious as to anyone else’s experience integrating Discourse into a mobile application with or without SSO, and what methods (if any) you found most useful throughout the process. I’m aware of Discourse’s compatibility with OAuth/2, although not aware of other potential protocols.

My apologies if this is in the wrong category!

「いいね!」 1

There is a new way of authentication. However the documentation is yet to be released.

「いいね!」 3

I’m going to update the documentation about delegated authentication soon, but I can give you some pointers right here.

First you need to open a browser session to discourse.site/user-api-key/new with the following parameters:

scopes: 'notifications,session_info,one_time_password',
client_id: YOUR_APP_CLIENT_ID,
nonce: GENERATED_NONCE,
auth_redirect: YOUR_APP_URL_SCHEME,
application_name: YOUR_APP_NAME,
push_url: PUSH_URL (if you are going to send PNs from Discourse to your app),
public_key: PUBLIC_KEY (generated in your app)

You can have a look at the implementation of our DiscourseMobile app for details on the above but the main idea is that your app will launch a browser screen to the URL above, asking the user to authenticate to the Discourse site and authorize your app access to it. Once user authorizes access, Discourse will redirect to YOUR_APP_URL_SCHEME?payload= with an encrypted payload. You’ll need to set up your app to decrypt the payload and store the authToken. In iOS, you should use ASWebAuthenticationSession | Apple Developer Documentation (I don’t know if there is an Android equivalent).

Your authToken can make API requests limited by the scopes requested initially, for a full list of scopes, please look under allow user api key scopes in site settings.

The one_time_password scope allows the authToken to make a request for a one-time-password. The endpoint for this is /user-api-key/otp with the parameters auth_redirect, application_name and public_key.

I will write a proper documentation shortly, but this should help you get started.

「いいね!」 5

@hosna + @pmusaraj Thank you both! I will pass this information along to our QA director.

「いいね!」 1

@pmusaraj こんにちは、すでに一般公開されている公式ドキュメントはありますか?さらに詳しく調べてみたいです。

今後数日でこれに挑戦します。成功するか失敗するか、その結果を更新します。もしガイドやヒントをお持ちの方がいれば、ぜひ共有してくださいね :slight_smile:

User API keys specification の「API キー生成フロー」のセクションをお探しかと思います。

「いいね!」 1

Penar さん、ご助言ありがとうございます。私はこの分野の専門家からはほど遠く、暗号化やこのような API を使った経験もほとんどありません。いくつかのパラメータをエンコードする方法について、ご助力いただけないでしょうか?DiscourseMobile アプリを拝見していますが、JavaScript を使ったことがないため、いくつかの点でつまずいています。

nonce と client_id は、単に 16 バイトと 32 バイトのランダムな文字列を hex エンコードしたものですか?
public_key について、生成方法のアドバイスはありますか?こちらのリソース を試していますが、SecKeyRef が得られるだけで、これを NSData に変換してから UTF8 エンコードするのでしょうか?

Swift や Objective-C のスニペットをお持ちではありませんか?自分で解決するつもりですが、すべてが新しい分野なので、どのようなご支援でも大変感謝いたします。

nonce はランダムな鍵です。generateNonce はこちらを参照してください:DiscourseMobile/js/site_manager.js at main · discourse/DiscourseMobile · GitHub

client_id はアプリの deviceToken で、GitHub - react-native-push-notification/ios: React Native Push Notification API for iOS. · GitHub を通じてアプリに渡されます。
public_key は GitHub - SamSaffron/react-native-key-pair · GitHub で生成されます。このライブラリは非常に小さく、関連する部分は Objective C で記述されています。

「いいね!」 4

やあ Penar さん、リンクをありがとう。とても役立ちました。
進捗は出ていますが、公開鍵のフォーマットが間違っているのではないかと思っています。このフォーマットはどう見えますか?

https://myserver.com/user-api-key/new?client_id=11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF&nonce=11223344556677889900AABBCCDDEEFF&application_name=AppName&public_key=-----BEGIN%20PUBLIC%20KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtoNwaYpbUcX1vqxPkxRA%0D1EyfLPxkKL6zgx4Fkk9zkYbTPTWQFuqy+O1EJtVnsW+Tx8iarFLI+ypghcx22nI0%0DN/hDFYsaT/xri+LLDc790uf2UtyolgBJfkyjJDxIXXy0pdpi6f2dgKMN2holDkxf%0DTUUnZad+wE8gT8IciX1XjU97MOngSV+IDeKPLomTuTiI1Z0hJe4WDww5+53ci4o4%0DoE5A79H/Fz/QY8vDLTcBNrQ6OdJYsRqhE5M+1sNmxpqDKT+9NcAPY7yphxm1iLuV%0Dm7c6K/xrbZExGDQd1qHvggT2ldMJIsmQEnleMdfuaYLh8+EYt8LNQ8X86V0Jj+9C%0DmQIDAQAB-----END%20PUBLIC%20KEY-----&auth_redirect=appname://auth&scopes=notifications,session_info,one_time_password

ログコンソールには以下が表示されています:
OpenSSL::PKey::RSAError (Neither PUB key nor PRIV key: nested asn1 error) /var/www/discourse/app/controllers/user_api_keys_controller.rb:189:in `initialize’

ありがとうございます。

この完全なことを実行するスクリプトを公開しました @xceph

テスト用ユーザー API キーの生成をご覧ください。

「いいね!」 3

ありがとうございます!進捗がありました。私の問題はパラメータのエンコーディングにありました。iOS の URLQueryAllowedCharacterSet を使用していたため、「/」や「+」がエンコードされませんでした。クラッシュしている行を特定するために Ruby スクリプトでテストを作成し、そこから逆算して解決できました。ありがとうございます!

「いいね!」 2

Penar が提案した ASWebAuthenticationSession を使用していますが、リダイレクトがうまく機能しないようです。呼び出しは期待通りに動作しているように見えます。「Authorize」ダイアログが表示され、クリックすると真っ白な画面に遷移します。これはリダイレクトを試行しているものと思われますが、画面が閉じず、コールバックに情報が送信されません。

カスタム URL は Safari からテストしたところ問題なく動作することを確認しました。さらに、auth_redirect を削除すると、「We have just generated a new user API key to use..」というサイトが表示されるため、リダイレクト以外の部分はすべて正常に動作しているようです。

また、おそらくこれに関連しているのですが、ディスカッションにカスタム URL を含むハイパーリンクを貼ろうとしてもクリックできないことに気づきました。カスタム URL を許可するための設定を見落としているのでしょうか?ご助言いただけますと幸いです :slight_smile:

追記:もちろん、質問直後にこれを見つけました。設定で「Allowed user api auth redirects」にカスタムスキーマを設定する必要があります。

真っ白な画面は、サーバーでエラーが発生している可能性が高いです。再度試す際は、Discourse サイトの /logs を確認してください。おそらくそこに何か記録があるはずです。おそらく、同じクライアント ID を複数回登録できないという問題に直面しているのでしょう。Discourse インスタンス上のそのクライアント ID を手動でクリアする必要があるかもしれませんが、現時点では Rails コンソールからのみ可能です。

「いいね!」 2

はい、それは管理パネルの「許可されたユーザー API 認証リダイレクト」設定からのものでした。それを設定する必要があり、無事に動作しました。

現在は認証できますが、iOS でペイロードのデコードに問題があります。受け取ったペイロードと秘密鍵を使って、Ruby や NodeJS でデコードして動作を確認することはできますが、iOS で直接デコードさせるのは、思っていたよりも難しいですね。

「いいね!」 1

当社のアプリのソースコードを見ると、デコードの例が記載されています。すべてが動作するようにするには、かなり複雑な量のコードが必要でした。

「いいね!」 4

ありがとうございます、すべて動作するように設定できました。後でコードスニペットを投稿して、iOS でネイティブにこれを実装しようとしている他の人の手助けになるようにします。ご助言に感謝します。

この方法で API トークンを作成した後、それを WebView でのログイン認証に使用することはできますか?アプリはそれをやっているものだと思っていましたが、まだその部分に取り組んでいます。API アクセスと通常の Web クライアント Reface での閲覧機能を、単一のログインで両方提供できるようにしようとしています。

「いいね!」 1