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.
Vou me dedicar a resolver exatamente isso nos próximos dias e atualizarei sobre meu sucesso ou fracasso. Se alguém tiver guias ou dicas, ficarei feliz em recebê-las
Ei Penar, obrigado pela orientação. Estou longe de ser um especialista nisso, não trabalhei muito com criptografia ou APIs como essa antes, e gostaria de saber se você poderia me ajudar com a codificação de alguns desses parâmetros? Estou analisando seu aplicativo DiscourseMobile, mas nunca usei JavaScript antes, então estou tendo algumas dificuldades.
nonce e client_id - Eles são apenas strings aleatórias de 16 e 32 bytes codificadas em hexadecimal?
public_key - Alguma orientação sobre como gerá-lo? Estou tentando usar o recurso aqui, o que me deixaria com um SecKeyRef. Devo convertê-lo para NSData e depois codificar em UTF8?
Você não teria algum trecho de código em Swift ou Objective-C, teria? Vou resolver isso, é só que tudo isso é novo para mim, então qualquer ajuda é muito apreciada.
Olá, Penar, obrigado pelos links, muito úteis.
Estou avançando, mas acredito que estou formatando minha chave pública incorretamente. Como está essa formatação?
Obrigado! Acabei de avançar. O meu problema estava na codificação dos parâmetros: eu estava usando o URLQueryAllowedCharacterSet do iOS, que não codifica “/” ou “+”. Assim que criei um script de teste em Ruby para isolar a linha onde estava ocorrendo o travamento, consegui trabalhar de trás para frente. Obrigado!
Parece que não consigo fazer o redirecionamento funcionar corretamente, usando o ASWebAuthenticationSession como o Penar sugeriu. As chamadas parecem funcionar conforme o esperado: obtenho a caixa de diálogo “Authorize” e, ao clicar nela, sou levado a uma tela branca em branco, que acredito ser a tentativa de fazer o redirecionamento, mas ela não fecha nem envia as informações para meu callback.
Testei e meu URL personalizado funciona bem no Safari. Além disso, se eu remover o auth_redirect, sou apresentado à página “Acabamos de gerar uma nova chave de API de usuário para usar…”, então tudo, exceto o redirecionamento, parece estar funcionando.
Além disso, e isso provavelmente está relacionado, notei que, se tentar colocar um hyperlink em uma discussão usando meu URL personalizado, ele não é clicável. Estou perdendo alguma configuração para permitir URLs personalizados? Qualquer ajuda é apreciada
edit: claro, eu encontrei isso imediatamente após perguntar. Nas configurações, você realmente precisa definir “Allowed user api auth redirects” para seu esquema personalizado.
Uma tela branca vazia é, muito provavelmente, um sinal de que o servidor está enfrentando um erro. Quando você tentar novamente, verifique os /logs do seu site Discourse; provavelmente há algo lá. Você provavelmente está enfrentando um problema onde o mesmo ID de cliente não pode ser registrado várias vezes. Pode ser necessário limpar manualmente esse ID de cliente na instância do Discourse, o que atualmente só é possível via console do Rails.
Sim, foi da configuração ‘Redirecionamentos de autenticação de API de usuário permitidos’ no painel de administração. Foi necessário configurar isso e funcionou perfeitamente.
Atualmente consigo autenticar, mas estou com dificuldades para decodificar o payload no iOS. Posso pegar o payload recebido e minha chave privada e decodificá-los em Ruby ou NodeJS para provar que está funcionando, mas fazer o iOS decodificá-lo diretamente está sendo mais complicado do que eu imaginava.
Se você olhar o código-fonte do nosso aplicativo, encontrará exemplos de como fazer a decodificação. Foi uma quantidade bastante complexa de código para fazer tudo funcionar.
Obrigado, consegui fazer tudo funcionar. Vou postar alguns trechos de código mais tarde para ajudar qualquer outra pessoa que queira fazer isso nativamente no iOS. Agradeço a orientação.
Depois de criar o token de API dessa forma, ele pode ser usado para autenticar um login em um webview? Eu assumi que era isso que o app estava fazendo, mas ainda estou trabalhando nessa parte. Estou tentando fornecer tanto o acesso à API quanto a capacidade de navegar pelo cliente web normal do Reface por meio de um único login.