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.
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.
Penar님, 조언해 주셔서 감사합니다. 저는 이 분야에 대해 전혀 모르는 초보자에 가깝습니다. 암호화나 이런 종류의 API를 사용해 본 적이 없어서, 일부 파라미터를 어떻게 인코딩해야 하는지 도움을 받을 수 있을까요? Penar님의 DiscourseMobile 앱을 보고 있는데, 저는 JS를 사용해 본 적이 없어서 몇 가지 어려움을 겪고 있습니다.
nonce와 client_id - 이건 단순히 16바이트와 32바이트의 랜덤 문자열을 hex로 인코딩한 것인가요?
public_key - 이걸 생성하는 방법에 대해 조언을 구할 수 있을까요? 이 리소스를 사용하려고 시도하고 있는데, 그러면 SecKeyRef가 남게 됩니다. 이걸 NSData로 변환한 다음 UTF8로 인코딩해야 하는 건가요?
혹시 Swift나 Objective-C 스니펫이 있을까요? 결국 해낼 수 있을 것 같지만, 저한테는 전부 새로운 것이라 작은 도움이라도 감사하겠습니다.
로그 콘솔에서는 다음과 같은 내용을 확인했습니다:
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’
감사합니다! 마침 문제를 해결했습니다. 파라미터 인코딩에 문제가 있었는데요, iOS의 URLQueryAllowedCharacterSet을 사용하고 있었는데 이 설정은 "/"나 "+"를 인코딩하지 않습니다. 크래시가 발생하는 줄을 분리하기 위해 테스트용 Ruby 스크립트를 작성한 후 역추적을 통해 원인을 파악할 수 있었습니다. 감사합니다!
Penar가 제안한 대로 ASWebAuthenticationSession을 사용했지만 리다이렉트가 제대로 작동하지 않는 것 같습니다. 호출은 예상대로 작동하는 것 같고, “Authorize” 다이얼로그가 표시되며 클릭하면 흰색 화면으로 이동합니다. 이는 리다이렉트를 시도하는 것으로 보이지만, 창이 닫히지 않고 콜백으로 정보가 전달되지 않습니다.
Safari에서 사용자 정의 URL이 정상적으로 작동하는지 테스트해 보았으며, auth_redirect를 제거하면 "We have just generated a new user API key to use.."라는 사이트가 표시됩니다. 따라서 리다이렉트를 제외한 모든 기능이 정상적으로 작동하는 것으로 보입니다.
또한, 아마도 관련이 있을 것 같은데, 토론에서 사용자 정의 URL을 하이퍼링크로 사용하려고 하면 클릭이 되지 않습니다. 사용자 정의 URL을 허용하기 위해 설정해야 할 항목이 있는지 모르겠네요. 도움이 필요해요
수정: 질문한 직후 바로 찾았습니다. 설정에서 "Allowed user api auth redirects"를 사용자 정의 스키마로 설정해야 합니다.
흰색 화면은 서버에서 오류가 발생했음을 나타내는 경우가 많습니다. 다시 시도할 때 Discourse 사이트의 /logs를 확인해 보세요. 아마도 관련 로그가 있을 것입니다. 동일한 클라이언트 ID를 여러 번 등록할 수 없는 문제에 직면했을 가능성이 큽니다. 현재는 Discourse 인스턴스에서 해당 클라이언트 ID를 수동으로 삭제해야 하며, 이는 레일스 콘솔(rails console)을 통해서만 가능합니다.