Protocollo di autenticazione re: integrazione app

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!

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

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.

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

@pmusaraj ciao, esiste già una documentazione ufficiale disponibile al pubblico? Mi piacerebbe approfondire.

Ne parlerò nei prossimi giorni e aggiornerò su esito positivo o negativo. Se qualcuno ha guide o consigli, sarei felice di riceverli :slight_smile:

Penso che tu stia cercando User API keys specification e in particolare la sezione “Flusso di generazione delle chiavi API”.

Ciao Penar, grazie per la guida. Sono molto lontano dall’essere un esperto in questa materia, non ho mai lavorato molto con la crittografia o con API come questa, e mi chiedevo se potessi aiutarmi a capire come codificare alcuni di questi parametri. Sto esaminando la tua app DiscourseMobile, ma non ho mai usato JavaScript prima, quindi sto riscontrando alcune difficoltà.

nonce e client_id: sono semplicemente stringhe casuali di 16 e 32 byte codificate in esadecimale?
public_key: hai qualche indicazione su come generarla? Sto cercando di usare la risorsa qui, che mi lascerebbe con un SecKeyRef. Dovrei convertirlo in NSData e poi codificarlo in UTF-8?

Per caso hai qualche frammento di codice in Swift o Objective-C? Ce la farò a risolverlo, ma è tutto nuovo per me, quindi ogni piccolo aiuto è apprezzato.

Il nonce è una chiave casuale; vedi generateNonce qui: DiscourseMobile/js/site_manager.js at main · discourse/DiscourseMobile · GitHub

Il client_id è il deviceToken dell’app, passato all’app tramite GitHub - react-native-push-notification/ios: React Native Push Notification API for iOS. · GitHub
Il public_key è generato da GitHub - SamSaffron/react-native-key-pair · GitHub; quella libreria è piuttosto piccola e le parti rilevanti sono in Objective C.

Ehi Penar, grazie per i link, molto utili.
Sto facendo progressi, ma credo di aver formattato male la mia chiave pubblica. Che ne pensi di questa formattazione?

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

Nel log della console vedo:
OpenSSL::PKey::RSAError (Né chiave PUB né chiave PRIV: errore ASN1 annidato) /var/www/discourse/app/controllers/user_api_keys_controller.rb:189:in `initialize’

Grazie

Ho appena pubblicato uno script per fare esattamente questa cosa @xceph.

Controlla Generazione di chiavi API utente per i test.

Grazie! Ho appena fatto progressi: il mio problema era nella codifica dei parametri. Stavo usando URLQueryAllowedCharacterSet di iOS, che non codifica “/” o “+”. Una volta creato uno script di test in Ruby per isolare la riga che causava il crash, sono riuscito a lavorare a ritroso. Grazie!

Non riesco a far funzionare correttamente il reindirizzamento, utilizzando ASWebAuthenticationSession come suggerito da Penar. Le chiamate sembrano funzionare come previsto: ottengo la finestra di dialogo “Autorizza” e, dopo averci fatto clic, vengo portato a una schermata bianca vuota, che presumo sia il tentativo di eseguire il reindirizzamento, ma non si chiude e non invia le informazioni al mio callback.

Ho testato che il mio URL personalizzato funzioni correttamente da Safari; inoltre, se rimuovo auth_redirect, mi viene mostrata la pagina “Abbiamo appena generato una nuova chiave API utente da utilizzare…”, quindi tutto sembra funzionare tranne il reindirizzamento.

Inoltre, e probabilmente è correlato, ho notato che se provo a inserire un collegamento ipertestuale in una discussione usando il mio URL personalizzato, non è cliccabile. Manca un’impostazione per consentire URL personalizzati? Qualsiasi aiuto è apprezzato :slight_smile:

Modifica: naturalmente, lo trovo immediatamente dopo aver chiesto. Nelle impostazioni è necessario impostare “Reindirizzamenti di autenticazione API utente consentiti” sullo schema personalizzato.

Uno schermo bianco vuoto è molto probabilmente un segno che il server sta riscontrando un errore. Quando riprovi, controlla i /logs del tuo sito Discourse: probabilmente c’è qualcosa lì. Probabilmente stai riscontrando un problema in cui lo stesso client ID non può essere registrato più volte. Potrebbe essere necessario cancellare manualmente quel client ID sull’istanza di Discourse; al momento è possibile solo tramite la console Rails.

Sì, proveniva dall’impostazione ‘Allowed user api auth redirects’ nel pannello di amministrazione; ho dovuto configurarla e ha funzionato perfettamente.

Attualmente riesco ad autenticarmi, ma ho problemi a decodificare il payload su iOS. Posso prendere il payload ricevuto e la mia chiave privata e decodificarli in Ruby o NodeJS per dimostrare che funziona, ma far sì che iOS lo decodifichi direttamente è più complicato di quanto pensassi.

Se guardate il codice sorgente della nostra app, troverete esempi su come eseguire la decodifica. È stato necessario scrivere una quantità di codice piuttosto complessa per far funzionare tutto correttamente.

Grazie, sono riuscito a far funzionare tutto. Più tardi pubblicherò alcuni frammenti di codice per aiutare chiunque altro voglia farlo in modo nativo su iOS. Apprezzo molto la vostra guida.

Una volta creato il token API in questo modo, può essere utilizzato per autenticare un accesso in una webview? Avevo assunto che fosse questo ciò che faceva l’app, ma sto ancora lavorando su quella parte. Sto cercando di fornire sia l’accesso API sia la possibilità di navigare tramite il normale client web Reface con un singolo accesso.