auth0 / omniauth-auth0

OmniAuth strategy to login with Auth0
MIT License
125 stars 67 forks source link

badly formed callback request to exchange authorization code for token #48

Closed ramieblatt closed 6 years ago

ramieblatt commented 7 years ago

Hi there,

I'm trying to implement omniauth-auth0 as a provider in our rails 4 app. I'm using the Auth0 lock widget in a modal to initiate the login process.

We use devise and omniauth and already successfully implement various providers like google, facebook and linkedin. I used a similar implementation to the one described here: https://github.com/auth0/omniauth-auth0/issues/6

For some reason, the omniauth-auth0 gem is generating a badly formed request to extract the access token from the authorization code and exchange it for the id token as described here: https://auth0.com/docs/client-auth/server-side-web#exhange-the-access_code-for-an-id_token

Here is an example trace of the request and response:

[www] [7ae2968b-XXXXX] [127.0.0.1] [USER: Unknown] [SESS: ecb26e0256aXXXXXX] Started GET "/accounts/auth/auth0/callback?code=XLbDDKKXXXXXX" for 127.0.0.1 at 2017-02-15 19:04:24 -0700
I, [2017-02-15T19:04:24.070708 #70029]  INFO -- omniauth: (auth0) Callback phase initiated.
E, [2017-02-15T19:04:24.845973 #70029] ERROR -- omniauth: (auth0) Authentication failure! invalid_credentials: OAuth2::Error, access_denied: Unauthorized
{"error":"access_denied","error_description":"Unauthorized"}

I can do this exchange myself in the terminal via a curl and it works fine. See below.

$ curl --request POST \
>   --url 'https://warmlyyours.auth0.com/oauth/token' \
>   --header 'content-type: application/json' \
>   --data '{"grant_type":"authorization_code","client_id": "zNZjT4aNDl24XXXXXXXX","client_secret": "AjGbpSc3XXXXXXXXXXX","code": "RTE6dqvXXXXXXX","redirect_uri": "https://www.x.me:3000/accounts/auth/auth0/callback"}'
{"access_token":"Wc7K8mXXXXXX","expires_in":86400,"id_token":"eyJ0eXAiOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","token_type":"Bearer"} 

Below are example log traces left in the Auth0 dashboard, the pattern is a failed exchange immediately following a successful login.

Summary
Occurred    15 hours ago at 2017-02-16 02:04:24.853 UTC
Type    **Failed Exchange**
Description Unauthorized
Connection  
Application zNZjT4aNDl24XXXXXXXX
User    

Raw
{
  "date": "2017-02-16T02:04:24.853Z",
  "type": "feacft",
  "description": "Unauthorized",
  "connection_id": "",
  "client_id": "zNZjT4aNDl24XXXXXXXX",
  "client_name": null,
  "ip": "73.14.174.238",
  "user_agent": "Faraday v0.9.2",
  "user_id": "",
  "user_name": ""
}

Summary
Occurred    15 hours ago at 2017-02-16 02:04:23.974 UTC
Type    **Success Login**
Description 
Connection  Username-Password-Authentication
Application XYZzNZjT4aNDl24XXXXXXXX
User    X@Y.com

Raw
{
  "date": "2017-02-16T02:04:23.974Z",
  "type": "s",
  "connection": "XYZ",
  "connection_id": "con_XYZ",
  "client_id": "zNZjT4aNDl24XXXXXXXX",
  "client_name": "XYZ",
  "ip": "73.14.X.Y",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Safari/602.1.50",
  "details": {
    "stats": {
      "loginsCount": 24
    }
  },
  "user_id": "auth0|XYZ",
  "user_name": "X@Y.com",
  "strategy": "auth0",
  "strategy_type": "database"
}

Any help would be appreciated!

Regards, Ramie

ramieblatt commented 7 years ago

Well, as a follow up, I tried following the Rails web app quick-start completely from scratch here: https://auth0.com/docs/quickstart/webapp/rails

I downloaded and configured a fresh seeded project from here: https://github.com/auth0-samples/auth0-rubyonrails-sample/tree/master/00-Starter-Seed

I configured a completely new account for this seed, created a user, verified their email etc. and tried to authenticate using the Rails web app seed project... and...

It. Just. Doesn't. Work.

This is all I can get, below, a callback from Auth0 with an authorization code, and then nothing, the omniauth-auth0 gem does not exchange the authorization code for a token or populate the omniauth hash and the seed app just redirects to the login page. The Auth0 dashboard logs show this as a "successful" login.

Started GET "/auth/auth0/callback?code=xH7l1ViqFx9PCTys" for ::1 at 2017-02-22 09:56:30 -0700
Processing by Auth0Controller#callback as HTML
  Parameters: {"code"=>"xH7l1VXXXXXX"}
callback: request.headers['Authorization']: 
callback: request.env['omniauth.auth']: 
Redirected to http://localhost:3000/dashboard
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

Started GET "/dashboard" for ::1 at 2017-02-22 09:56:30 -0700
Processing by DashboardController#show as HTML
Redirected to http://localhost:3000/
Filter chain halted as :logged_in_using_omniauth? rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

Does anyone at Auth0 want to address this? My support ticket with Auth0 has been sitting there for a week with no response. There have never been any responses to any issues reported here in the omniauth-auth0 github repo by the Auth0 committers. Is anyone at Auth0 actively working on this gem? Is Auth0 interested in customers that use Rails?

For context, we've successfully integrated omniauth-facebook, omniauth-google-oauth2, omniauth-linkedin, omniauth-twitter and so on into our stack in production over the years, so we feel like this is a real issue with the omniauth-auth0 gem, not a 'newbie' question.

Regards, Ramie

ahmedissa commented 7 years ago

i have the same issue.

ahmedissa commented 7 years ago

i solved it :) ,, just generate a new token it will resolve the issue.

ClaudioFloreani commented 7 years ago

Why is this issue still open?

jakeNiemiec commented 7 years ago

Ahmad's solution did not solve the original issue. On Mon, Mar 27, 2017 at 5:03 AM Claudio Floreani notifications@github.com wrote:

Why is this issue still open?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/auth0/omniauth-auth0/issues/48#issuecomment-289409432, or mute the thread https://github.com/notifications/unsubscribe-auth/AQAS75exCciCMqXRUhvJRzIZE8zXJd35ks5rp4lwgaJpZM4MDR-w .

cocojoe commented 6 years ago

Sorry for the long delay, picking up on this repo now. We will be going through some updates soon.

cocojoe commented 6 years ago

@joshcanhelp ensure the QS and sample works after updates and lets circle back.

jakeNiemiec commented 6 years ago

Sorry, we have already dropped Auth0 for lack of support :/. Perhaps we will give it another try sometime.

joshcanhelp commented 6 years ago

@jakeNiemiec - Sorry to hear that but totally understand.

For anyone else having this issue ... this gem was built to use the universal login page, not Lock. The Rails quickstart uses this method (redirecting to a login page and back). That said, Lock should work just fine as well, assuming it's configured properly. I'm testing that now and will post back if I find an issue or have a working config I can share.

joshcanhelp commented 6 years ago

So, I can confirm that this gem works fine with Lock when configured properly. Here is the controller to grab the values Lock needs:

https://github.com/joshcanhelp/auth0-ruby-basic/blob/master/app/controllers/static_pages_controller.rb#L7

Note the SessionsHelper::get_state() method used which generates a state value and stores it in the session so OmniAuth can verify it's that same as what's sent to and returned by Auth0 (more on state validation here).

Assuming we already have jQuery globally, here is how Lock is initialized:

https://github.com/joshcanhelp/auth0-ruby-basic/blob/master/app/views/static_pages/lock.html.erb

In the code above, I see Parameters: {"code"=>"xH7l1VXXXXXX"} but no state in there. Since state is enforced in OmniAuth, it's possible that you're not generating and storing it. I usually see an error mentioning "CSRF" when I do that.

Closing this for now. Please feel free to post back if this is still an issue for anyone.

cassiopagnoncelli commented 6 years ago

Same error here. Abruptly stopped working last week, now looks incredibly foggy. Followed the Rails tutorial without success like you guys.

Does anyone has a clue how to get a simple authentication Rails app working?

joshcanhelp commented 6 years ago

@cassiopagnoncelli - Like I mentioned above, I have this working locally by following the quickstart. It sounds like you and others are still having a problem so I'll walk through that again and see if there are any steps missing.

For anyone that's still having this issue, can you post your Ruby and Rails versions used?

coros-sanborn commented 6 years ago

Having same problem here. Everything worked fine with the embedded login with Lock 9. Now that I've upgraded to Lock 11, lock will not redirect after authentication; although I've confirmed through the Auth0 dashboard logs and the Lock UI itself that the user was successfully authenticated. I looked at the Rails quickstart, but that example does not show what to do for embedded login pages - it only shows how to redirects to the universal login page.

Since Lock 9 allowed embedded login pages, it only makes sense that Lock 11 should allow the same AND the changes should be documented.

Using: Rails 4.2.7.1, Ruby 2.3.1

Any help with this will be appreciated. I've spent over a week trying to upgrade and we're at the point where we may need to consider an other option.

cassiopagnoncelli commented 6 years ago

@joshcanhelp Thing is, without changing Auth0 code nor other configuration last deploy here got authentication never to work again on production.

Turns out Auth0 actually sends the code back to the webapp upon providing the credentials, then it yields Bad Gateway. Because most production servers, like mine, sit behind a load balancer / reverse proxy so it may need extra attention there.

Would like to hear from you guys having your Rails app behind Nginx with https redirection how you're solving the problem.

Using: Ruby 2.5.0 Rails 5.2.0 nginx 1.12.1

joshcanhelp commented 6 years ago

I appreciate all the extra information on this everyone and apologies for the trouble. I wasn't aware that this was such a wide-spread issue.

Troubleshooting this issue and making sure the quickstart is clear is a high priority. If anyone has any additional information, please post that here. Otherwise, expect to hear back in a few days with a fix or request for more information.

Thank you!

jakeNiemiec commented 6 years ago

Would like to hear from you guys having your Rails app behind Nginx with https redirection how you're solving the problem.

We had the same setup, did not find a solution.

coros-sanborn commented 6 years ago

FYI. I did try using the hosted page for universal login and I saw that the version of lock is v9 (which is supposed to be deprecated). I tried updating lock to v11 and I could not get it to redirect to my rails app either. I don't have a good example of what the configuration is supposed to look like for the universal login with lock 11, so it could be a configuration issue.

Either way, it would be very helpful if there were documentation.

Thanks.

joshcanhelp commented 6 years ago

@coros-sanborn - Lock on the universal login page does not need to be upgraded or changed in any way. The deprecation relates to embedded Lock, meaning a Lock widget on your site, and pertains to cross-origin authentication. Since the universal login page is on the same domain, there's no deprecation there.

Did the universal login page work? That's the way we recommend setting it up (and the way my test app was setup). If not, was it the same issue?

joshcanhelp commented 6 years ago

Rails app behind Nginx with https redirection how you're solving the problem.

@cassiopagnoncelli @jakeNiemiec - Do you mean that you're redirecting from http to https? Are you using an http callback URL that redirects? I'm not totally clear what you mean here.

coros-sanborn commented 6 years ago

@joshcanhelp - After a bit of a closer look, the universal login page "wants" to work, however it's not returning all the needed data (like before), specifically the user roles. With lock 9, and the embedded login page we were getting the role information for the user, now we do not get that information so the app errors out.

Ideally, we want the embedded app to work, as it did with Lock 9. However, if we're forced to use the universal login then I need to to return the same information as before: provider, uid, name, email, email_verified, roles and app name (we have more than one app using auth0).

Is there a way to specify the attributes that get returned?

coros-sanborn commented 6 years ago

@joshcanhelp - One other issue with the Universal login. If I bypass the roles (just for testing). I do see an other problem with the universal login.

When creating an account and logging in for the first time a popup window comes up with the following message: "Hi email@example.com, "XXXX" is requesting access to your "XXX" tenant"

We do not want that window to appear. This will be confusing to our users. How can we get rid of that window?

joshcanhelp commented 6 years ago

After a bit of a closer look, the universal login page "wants" to work, however it's not returning all the needed data (like before), specifically the user roles. With lock 9, and the embedded login page we were getting the role information for the user, now we do not get that information so the app errors out.

By default, the ID token won't include any user_metadata unless you have custom claims set up. That's for the universal page and for Lock. The universal page can do the same kind of authentication as Lock, and use the same callback URL, assuming they're both being asked to do the same thing. So, to get user_metadata (assuming that's where the role is stored, if not let me know), you'll either need to add that to the ID token or you'll need a Client Credentials grant with the Management API to pull that down or the custom claim I linked to above.

However, if we're forced to use the universal login then I need to to return the same information as before: provider, uid, name, email, email_verified, roles and app name (we have more than one app using auth0).

We recommend using the universal page for a number of reasons but Lock should work fine. The basic ID token can store provider, uid, name, email, and email_verified, see above for the rest. I'm not sure where the app name would come from but you can use the client ID with the Management API, as explained above (or just store that mapping in your app).

When creating an account and logging in for the first time a popup window comes up with the following message: "Hi email@example.com, "XXXX" is requesting access to your "XXX" tenant"

Is that using localhost? You'll see that modal in this case but should not otherwise.

coros-sanborn commented 6 years ago

Thanks for the reply. I guess the biggest issue is that I used to get this information back with embedded Lock 9 without having to create custom claims or use the universal login page.

We used to get the app_metadata back which included the roles: data[:extra][:raw_info][:app_metadata][:myAppName][:roles]

The universal login (which is v9) should at least work and return the same information as embedded lock v9 - which it does not (since I no longer get the app_metadata).

To be clear, I'm only looking at the universal login as a last resort.

The issues stated in this thread still exist. I have a rails 4 app that had the embedded login page with lock 9. It worked fine for years. It stopped working in the last couple weeks because lock 9 was deprecated. As soon as I upgraded to lock 11 the page will no longer redirect, even if the user is authenticated.

This is the problem that I and many others are having and we really need a resolution. If lock 9 worked then upgrading to lock 11 should work, maybe with a few tweaks, but the entire app should not fail. And to add to the challenge there is not any documentation on how to configure the embedded login with Rails. The quickstart example is only for using the universal login page.

I'd be happy to provide any information to try to help get the embedded login working with Rails, since this is our preferred method for using Auth0. In the mean time I can use the universal lock page, but I need to get the same app_metadata as before.

Thank you.

joshcanhelp commented 6 years ago

@coros-sanborn - I'm worried we're getting a number of issues mixed together here. This one was created last year so it's not related to the deprecation. I opened up a new issue here so we can work together to figure this out.

@cassiopagnoncelli - You might be getting a similar error (though it doesn't sound like it based on your last comment) but it sounds like a different issue from the original one posted here. Would you mind opening up a new issue with the details, plus an answer to my question above? We want this to work in as many places as possible and we're happy to help you figure out how to do that.

For everyone else ... I just walked through the quickstart from start to finish and, besides a few gaps related mostly to views (just put through a PR to fix that) I was able to get it working without an issue. Rails 5.2.0, Ruby 2.5.1p57, just running on Puma locally. Like the quickstart, this is using the universal login page.

If you're using Lock (including @coros-sanborn) and things stopped working as expected last week, that's likely due to the deprecation of Lock 9. We have a migration guide here that walks through what changed and how to fix it in detail. You can also turn that API back on under your tenant settings but that will only last until Monday when it goes dark for good.

joshcanhelp commented 6 years ago

We've updated the quickstart based on the feedback here and tested it start to finish a few times. This thread discusses a number of different issues so if you have a specific one we can help with, please open a new thread with reproduction steps and we'll take a look.

jakeNiemiec commented 6 years ago

I was able to get it working without an issue. Rails 5.2.0 Ruby 2.5.1p57, just running on Puma locally.

Myself and 2 other posters here are all reporting that it didn't work on Rails 4.x. Assets are served very differently between the two.

joshcanhelp commented 6 years ago

@jakeNiemiec - One of the posters above had an issue that was not related to the Rails version, rather a legacy authentication API endpoint.

Still, we want this to work on as many platforms as possible and, if needed, provide tutorials/documentation for older, supported versions of languages and frameworks. To that end, I just walked through this quickstart using Ruby 2.5.1 and Rails 4.2.10 and was able to get it working with no changes to the provided steps.