Closed rjocoleman closed 6 years ago
This might or not applied to you, but we ran in a similar problem using omniauth-auth0 and the devise omniauth integration. In our case, we manually generated the authorize url instead of relying on the omniauth route helper (user_auth0_omniauth_authorize_path
). Omniauth is taking care of generating a state query parameter, storing it in the session and comparing when the request comes back.
You will want to make sure that this method https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L51 gets called as part of the request generation.
I'm having the same problem. It seems that the Auth0 Lock dialog is broken with this version of the gem. It works if I do what the README says and just redirect the user to /auth/auth0
, which uses the hosted Login page.
As far as I can tell, OmniAuth-OAuth2 is expecting the callback URL to include a state
query-string parameter, but it doesn't. I am still trying to track down why that is. Any help appreciated.
Auth0 will return the state value if you pass it as a parameter when you send the user to the Auth0 authentication page. For it to work, the authorize request should look something like:
https://<account>.auth0.com/authorize?auth0Client=<auth0Client>&client_id=<clientId>&redirect_uri=<callback_uri>&response_type=code&state=<uuid>
callback_uri => https://<host>/users/auth/auth0/callback
If you use the user_auth0_omniauth_authorize_path
helper, it will automatically generate the state
query parameter and save it in the session so that it can be validated when the callback is called.
In our case, it looks something like this:
https://<host>/login
and have this hit an AuthenticationController
in the Rails app (in our case, we put it in the same controller that handles the auth0 callback). user_auth0_omniauth_authorize_path
. At this point, OmniAuth-OAuth2 generates the Auth0 authorize url, including a unique state
query parameter that it store in the session.class AuthenticationController < Devise::OmniauthCallbacksController
def login
redirect user_auth0_omniauth_authorize_path
end
...
end
I hope it helps.
@pouellet thanks so much, that really did help! I'm now provider_ignores_state = false
👍
Thanks @pouellet. That seems to be the same flow as linking the user to /auth/auth0
? I am trying to use this gem with Auth0's Lock widget.
@rjocoleman mentioned using provider_ignores_state = false
. I'm still not convinced this is a safe option to use - any malicious site can form a valid request to Auth0 and authenticate a user against the origin site.
That said, I'm not sure if this gem is where this problem needs to be tackled. Perhaps provider_ignores_state = false
should be set, to turn off omniauth's csrf protection, and then a custom CSRF solution put in place, that adds a CSRF protection token into the state
param of the Lock widget.
@MattFenelon I was using lock.js, but I took it out and started using the hosted login page.
Take a look at both the authorize_params
(https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L51-L60 and https://github.com/auth0/omniauth-auth0/blob/master/lib/omniauth/strategies/auth0.rb#L53-L57) methods, make sure it's called and add a param state
to your lockjs redirectUrl
.
This is not working for me. I pass a state
param to the auth0 authorization URL, but it doesn't pass it back. The only param I get is code
. Is there a setting in my auth0 account that's preventing it from being sent back?
I'm using lock-passwordless-2.2.min.js
on the Auth0 hosted login page, btw. Here's the relevant script part:
<script>
// Decode utf8 characters properly
var config = JSON.parse(decodeURIComponent(escape(window.atob('@@config@@'))));
config.extraParams = config.extraParams || {};
config.responseType = config.extraParams.response_type;
config.dict = {
email: {
headerText: "Enter your email to sign in"
},
title: "My Title"
};
config.closeable = false;
var connection = config.connection;
var prompt = config.prompt;
var loginHint = config.extraParams.login_hint;
var lock = new Auth0LockPasswordless('key', 'my-domain.auth0.com');
lock.emailcode(config);
</script>
OK, I figured this out. When passing a state
parameter to the auth0 hosted login page, it gets put in the extraParams
object after parsing the @@config@@
. I simply added an authParams
object to the lock config, including a state
key with the value set to config.extraParams.state
.
Here's the updated script example:
<script>
// Decode utf8 characters properly
var config = JSON.parse(decodeURIComponent(escape(window.atob('@@config@@'))));
config.extraParams = config.extraParams || {};
config.responseType = config.extraParams.response_type;
config.dict = {
email: {
headerText: "Enter your email to sign in"
},
title: "My Title"
};
config.closeable = false;
config.authParams = {
scope: 'openid profile', // Learn about scopes: https://auth0.com/docs/scopes
state: config.extraParams.state
};
var connection = config.connection;
var prompt = config.prompt;
var loginHint = config.extraParams.login_hint;
var lock = new Auth0LockPasswordless('key', 'my-domain.auth0.com');
lock.emailcode(config);
</script>
Maybe someone from the Auth0 team can comment on why the state
url param is stuffed into an extraParams
object.
I got CSRF working w/ Lock.
omniauth (1.6.1) omniauth-auth0 (2.0.0) omniauth-oauth2 (1.4.0) lock.min.js (10.9.1)
module SessionHelper
def state_meta_tag
state = SecureRandom.hex(24)
session['omniauth.state'] = state
tag('meta', name: 'state', content: state)
end
end
<%= csrf_meta_tags %>
<%= state_meta_tag %>
var options = {
auth: {
redirectUrl: '<%= Rails.application.routes.url_helpers.auth_callback_url(:oauth2) %>',
responseType: 'code',
params: {
scope: 'openid email',
state: $('meta[name="state"]').attr('content')
}
},
theme: {
primaryColor: '#EA5A52'
}
};
var lock = new Auth0Lock('<%= ENV['AUTH0_CLIENT_ID'] %>', '<%= ENV['AUTH0_DOMAIN'] %>', options);
lock.show();
@atwoodjw can you specify which version of the omniauth gems? (omniauth, omniauth-auth0, omniauth-oauth2)
The problem arise only when switching to omniauth-auth0 version 2.0.0, so at least some upgrading instructions should be provided for customers going to the next major release.
Sure.
omniauth (1.6.1) omniauth-auth0 (2.0.0) omniauth-oauth2 (1.4.0) lock.min.js (10.9.1)
Yes, the issue only arrises in omniauth-auth0 (2.0.0) because provider_ignores_state = true
is no longer set by default. CSRF protection wasn't enable by default in earlier versions.
Above @atwoodjw worked like a charm.
But I am not able to achieve this for IdP initiated SSO as the IdP first authenticate and the callback URL is called directly from auth0. There is no way that you can store any state param in session as the request is initiated from IdP. Request to suggest any best practices
@errfanwadia I ran into similar issue when doing impersonation. Everything happens on the Auth0 side before the callback to omniauth. The only solution I'm aware of so far was to disable the state check
@joshcanhelp Needs sorted.
Sorry for the long delay, picking up on this repo now. We will be going through some updates soon.
Chiming in here since the fixes are using old versions of our libraries that should be updated. Again, apologies for the long delay in response here.
See my comment here for an example of how to use this library with Lock. Make sure you're using the latest major/minor version of Lock, preferably the latest (11.7.x as of this writing). This library includes Passwordless now as well, no need for the separate library.
That said ... you're best off using the universal login page (redirecting to /authorize
) as described in our Rails quickstart.
Thank you @atwoodjw for the example posted!
@hoverlover - those are parameters sent to the /authorize
endpoint, hence the naming. See the example above or mine linked here as that naming has changed a bit (auth.params.state
).
@errfanwadia - If you're still struggling with this, please open a new issue with information about your setup so we can troubleshoot that.
https://
class AuthenticationController < Devise::OmniauthCallbacksController
def login redirect user_auth0_omniauth_authorize_path end
... end
class AuthenticationController < Devise::OmniauthCallbacksController
def login redirect user_auth0_omniauth_authorize_path end
... end
Today I tried to sign in to https://code.videolan.org by using github.com. I got a pin , but it failed with CSRF detected. What should I do? How should I understand your comment? Is it fixed or not? Or is it a bug on https://code.videolan.org?
Using
omniauth-auth0
v2.0.0 but otherwise following the Rails 5 guides in the docs leads to acsrf_detected
error coming out of omniauth.provider_ignores_state = true
used to be set in the provider by default. This was removed in v2.0.0. Setting this explicitly avoids the CSRF detected error but it doesn't seem like a good idea.Is there another suggested implementation to avoid setting
provider_ignores_state = true
?