Implement discourse Apple login using API

AI-generated summary

wings is trying to implement Apple login using API in Discourse. After installing the plugin and following the instructions, they encountered an error Authorization timed out, or you have switched browsers. Please try again. and a csrf_detected error in the logs.

@david explained that Apple authentication (and other auth methods in Discourse) are not designed to be used via the API, but rather directly by end-users in a supported browser.

wings clarified that they want to create an API for Apple login to be used by a mobile app to access the Discourse API. They are trying to replicate the process of logging in with email and password using the Discourse APIs.

@david advised against trying to ‘fake’ a user session and recommended using the user API keys system, which will allow Discourse to handle the authentication logic and provide per-user API keys.

Hi, I am working on building an API for Discourse login using Apple. I have already installed the plugin and followed the instructions from Discourse Apple Authentication. It works fine when logging into Discourse using an Apple account in website.

Upon checking the flow of Apple login from the web, I noticed that it redirects to the Apple page for login, obtains a code generated from Apple upon successful login, and then redirects to:

POST {{discourse_host}}/auth/apple/callback with parameters state:{state}, code:{code from Apple}

After that, it redirects to GET {{discourse_host}}/auth/apple/callback?code={{code from Apple}}&state={state}, generating a new cookie that will be used in the Discourse API.

from this flow I expect it will generate a new cookie after the call /auth/apple/callback

But when I try to call the API it will show the error Authorization timed out, or you have switched browsers. Please try again.

So I tried again with a new code generated by Apple but still got the same error

And when I check the log it show

Started GET "/auth/apple/callback?code=c32f105b5084d42b8bd3e7051873ddb55.0.rrzxz.pChPU9zGlXIHHhgEXLiA5g&state=fbi3bbboud" for>
(apple) Setup endpoint detected, running now.
(apple) Callback phase initiated.
(apple) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
Started GET "/auth/failure?message=csrf_detected&strategy=apple" for 123.253.233.16 at 2023-11-27 06:10:28 +0000
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"message"=>"csrf_detected", "strategy"=>"apple"}
  Rendered users/omniauth_callbacks/failure.html.erb within layouts/no_ember (Duration: 4.1ms | Allocations: 17)
  Rendered layout layouts/no_ember.html.erb (Duration: 57.5ms | Allocations: 2882)

Message (47 copies reported)

(apple) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

Backtrace

/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:163:in `log'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:486:in `fail!'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-oauth2-1.7.3/lib/omniauth/strategies/oauth2.rb:87:in `callback_phase'
/var/www/discourse/plugins/discourse-apple-auth/lib/omniauth_apple.rb:60:in `callback_phase'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:238:in `callback_call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:189:in `call!'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:192:in `call!'

So I want to ask if this direction to using discourse apple sign-in using API is already correct and how I solve the problem with csrf_detected error

The Apple authentication (and indeed, all other auth methods in DIscourse) are not designed to be used via the API. They should be used directly be end-users in a supported browser.

What problem are you trying to solve here? Perhaps we can work out an alternative solution?

Hi @david, thanks for your reply. What I want to achieve here is to create an API for Apple login that will be used by the mobile app to access the Discourse API.

For using the Discourse API to log in with email and password, it works fine using these two Discourse APIs:

  1. {{discourse_host}}/session/csrf.json: This API returns a cookie and CSRF code, which will be used for login using the next API.
  2. {{discourse_host}}/session: This API returns a new cookie that can be used to access other Discourse APIs.
Csrf API

Session

I expect it to be similar to Apple login in Discourse, where I make a request to the Discourse API to generate the _t cookie.

Hi @david, do you have a solution for my issue?

I’m afraid there’s no easy answer. Authentication APIs like this are specifically designed to avoid them being triggered without real user interaction on the web.

For your use case, the more common solution would be to use the user API keys system. That will allow Discourse to handle 100% of the authentication logic, and will give your app some per-user API keys. That strategy should be much more robust than trying to ‘fake’ a user session.