Authentication Protocol re: App Integration

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 Like

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

3 Likes

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 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 Likes

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

1 Like

@pmusaraj hey, is there already any official documentation available to the public? I’d love to dig deeper.

I’m going to tackle this exact thing over the next few days, I will update on my success or failure. If anyone has any guides or pointers I’d welcome them :slight_smile:

I think you’re looking for User API keys specification and specifically the section " API key generation flow".

1 Like

Hey Penar, thanks for the guidance, I’m far from an expect in this stuff, I havent done much with any cryptography, or apis like this before and was wondering if you could provide some help as to how to encode some of these parameters? I’m looking at your DiscourseMobile app but I have never used JS before, so I’m having a few difficulties.

nonce and client_id - Are these just random 16 and 32 byte strings hex encoded?
public_key - Any guidance on how to generate this? I’m trying to use the resource here which would leave me with a SecKeyRef, am I to convert this to NSData and then UTF8 encode?

Wouldn’t happen to have any snippets in swift or objective c would you? I’ll figure this out, its just all new to me so any bit of help is appreciated.

nonce is a random key, see generateNonce here: https://github.com/discourse/DiscourseMobile/blob/master/js/site_manager.js#L348-L354

client_id is the app’s deviceToken, it is passed to the app via https://github.com/react-native-community/push-notification-ios
public_key is generated by https://github.com/SamSaffron/react-native-key-pair, that library is pretty small, and the relevant parts are in Objective C.

4 Likes

Hey Penar, thanks for the links very useful.
I’m making progress but believe I’m formatting my public key incorrectly, how does the formatting on this look?

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

In the log console I see :
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’

Thanks

I just published a script to do this exact thing @xceph.

Check Generating User API Keys for testing.

3 Likes

Thanks! I just made progress, my issue was in the encoding of the parameters, I was using iOS’s URLQueryAllowedCharacterSet, which does not encode “/” or “+”, once I created a test ruby script to isolate out the line I was crashing on I was able to work backwards. Thanks!

2 Likes

Can’t seem to get the redirect to work properly, using the ASWebAuthenticationSession as Penar suggested. The calls seems to work as expect, I get the “Authorize” dialog and upon clicking it I am brought to a plain white screen, which I expect is the attempt to do the redirect, but it does not close and send the information to my callback.

I’ve tested that my custom URL works fine from Safari, and furthermore if I remove the auth_redirect I am presented with the “We have just generated a new user API key to use…” site, so everything other than the redirect seems to be working.

Furthermore, and this is likely related, I’ve noticed if I try and put a hyperlink in a discussion using my custom URL it is not clickable, am I missing a setting to allow for custom urls, any help is appreciated :slight_smile:

edit: of course, i find this immedatly after asking. In settings you do indeed need to set “Allowed user api auth redirects” to your custom schema.

Plain white screen is most likely a sign that the server is running into an error. When you try this again, check your Discourse site’s /logs, there’s probably something there. You probably are running into an issue where the same client id cannot be registered multiple times. Might need to manually clear that client ID on the Discourse instance, only doable via rails console ATM.

2 Likes

Yea it was form the : “Allowed user api auth redirects” setting in the admin panel, needed to set that and it worked fine.

Currently I can authenticate, but having trouble decoding the payload on iOS. I can take the received payload and my private key and decode them in Ruby or NodeJS to prove its working, but getting getting iOS to decode it directly is trickier than I thought for me.

1 Like

If you look at the source code for our app there are examples on how to do the decoding, it was a rather complicated amount of code to get it all working.

4 Likes

Thanks, I managed to get it all working, I’ll post some snippets later to help anyone else looking to do this natively on iOS. Appreciate the guidance.

Once you’ve created the API token in this way can it be used to authenticate a login in a webview? I had assumed that’s what the app was doing but I’m still workin on that piece now. Trying to provide both API access and the ability to browse via the normal web Clint reface via a single login

1 Like