User (patron) getting authorization error message

do you know what the problem is?

Yes. It looks like one of the required params not correctly carry forwarded across the requests. I think it’s lost while coming back from Patreon after the authentication flow.

1 Like

will it take long to fix?

It shouldn’t take much time. I will try to fix it asap.

3 Likes

did what you do stop or remove the viewport? I cannot remove the option of the address bar anymore by adding it to home screen. And it keeps asking for authorizing

No I didn’t receive anything from the viewport for this fix. I think it’s unrelated.

My user is still unable to access on any device as of this morning (10.19.18)

Hi @caduspa,

Run the below commands in SSH console and try the login again. Let me know if the problem persist.

./launcher enter app
rails c
SiteSetting.patreon_login_ignore_state = true
4 Likes

You are most kind. Sadly, that is above from my level of knowledge. (I’m a classic “tell me which button to push”). I’ll see if I can patch together the know how from a few searches.

1 Like

I’m having this issue on our community and just made the changes above. I’ll ask for more testing, and let you know what I find out.

1 Like

I run into this issue, but not with patreon as sign in provider. Everything else seems exactly alike though, the issue is only on mobile devices.

I’m using the OIDC plugin to authenticate through, see: OpenID Connect Authentication Plugin, to authenticate with Okta.

From the discourse error logs that I can visit at https://discourse.example.com/logs/, I find an error that is logged whenever I reproduce our issue.

I read the following article about it: Web security essentials - CSRF (Cross site request forgery) 🔑 - Soham's blog

I’m currently not confident about what goes on, but I guess that we are loosing a CSRF token at some point using the mobile auth flow.

This also makes me suspect that SiteSetting.patreon_login_ignore_state = true is an insecure way to bypass the issue we are having.

Error message

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

Note that CSRF stands for Cross-Site Request Forgery. And from googling I learned that:

CSRF attacks target functionality that causes a state change on the server, such as changing the victim’s email address or password, or purchasing something.

Error stack trace

/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/logster-2.0.1/lib/logster/logger.rb:101:in `add_with_opts'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/logster-2.0.1/lib/logster/logger.rb:52:in `add'
/usr/local/lib/ruby/2.5.0/logger.rb:545:in `error'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:163:in `log'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:486:in `fail!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-oauth2-1.6.0/lib/omniauth/strategies/oauth2.rb:71:in `callback_phase'
/var/www/discourse/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb:97:in `callback_phase'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:238:in `callback_call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:189:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/omniauth-1.9.0/lib/omniauth/builder.rb:64:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:30:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/tempfile_reaper.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/conditional_get.rb:25:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/head.rb:12:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:214:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/session/abstract/id.rb:232:in `context'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/session/abstract/id.rb:226:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/cookies.rb:670:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/callbacks.rb:98:in `run_callbacks'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/debug_exceptions.rb:61:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/logster-2.0.1/lib/logster/middleware/reporter.rb:30:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/rack/logger.rb:38:in `call_app'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:16:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:29:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/method_override.rb:22:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/executor.rb:14:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/sendfile.rb:111:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-mini-profiler-1.0.2/lib/mini_profiler/profiler.rb:171:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.0/lib/message_bus/rack/middleware.rb:57:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:182:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/engine.rb:524:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/railtie.rb:190:in `public_send'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/railtie.rb:190:in `method_missing'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/urlmap.rb:68:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/urlmap.rb:53:in `each'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/rack-2.0.6/lib/rack/urlmap.rb:53:in `call'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:606:in `process_client'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:701:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:549:in `spawn_missing_workers'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:142:in `start'
/var/www/discourse/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/bin/unicorn:126:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `load'
/var/www/discourse/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `<main>'
2 Likes

Can confirm we’re seeing very similar things too without using patreon to authenticate - we just use the standard oauth plugin. Only mobile users see this.

2 Likes

Here’s a brief outline of how the “state” token is used. It’s part of the OAuth2 specification, so is used for all Discourse’s social login methods, including Patreon, OIDC and OAuth2.

  1. User clicks “login” on Discourse

  2. Discourse generates a random string (a “state token”), and stores it against the user’s browser session

  3. Discourse redirects the user to the auth provider, passing along a copy of the state token

  4. User logs in, and is redirected back to Discourse. The provider passes back the state token

  5. Discourse checks that the received state token matches the one it stored against the user’s browser session earlier. If they do not match, this is considered an CSRF attack.

So, the most likely way this can break in practice, is if the user starts/ends the process in a different browser session. On a desktop this is pretty much impossible, but mobile operating systems tend to have different browser sessions for PWAs vs. browsers vs. native apps, which could be causing this issue.

Do you know whether these users are using the Discourse app, or an ‘installed’ PWA?

6 Likes

Thank you for writing down the steps regarding the state @david!

I’m experiencing this with the OIDC plugin, that in turn auths with Okta as IdP, that in turns delegates auth to Azure AD v2.0 OpenID Connect. And it only happens on IPhone as compared to Android devices I think (but this needs to be confirmed further, I have not tested it myself on Android).

It also happens on IPhone no matter if I utilize Safari och Chrome. I have not installed an Discourse app, and I have not utilized discourse on my mobile as an webpage-application (PWA?) but instead simply utilized my Chrome app and opened up my deployed discourse.

1 Like

I’d love to get to the bottom of this, but so far I haven’t managed to reproduce the issue. It’s certainly interesting that you’re seeing this problem with OAuth2 and OIDC, which suggests this issue is not specific to patreon.

@simonv3 and @consideRatio do you have a consistent way to reproduce the issue? And if so, would it be possible for me to access the site in question? (Feel free to PM me if you’d rather not make it public)

3 Likes

I have a feeling that this issue could be related to this Safari bug

Fixed Same-Site Lax cookies to be sent with cross-site redirect from a client-initiated load

It was fixed in release 77 of their technology preview, so hopefully it will be part of the next iOS/macOS release.

6 Likes

I’ll keep an eye out for similar problems being reported. It hasn’t been reported in a while, but that doesn’t mean it’s not being experienced - probably just that most people know their way around it by now.

4 Likes

Heh, just had it reported today. I’ll let them know that maybe it’s a bug in iOS, and ask them if it still happens if/when they upgrade.

3 Likes

@simonv3 and @consideRatio, are you still seeing this error? I am hoping that it has been mostly solved by iOS 12.2, but there may still be some outstanding issues.

2 Likes

I had two issues, one with my OIDC provider, and one resolved with iOS 12.2 :wink:

2 Likes