New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constantly getting "Invalid Credentials: invalid_grant" #732

Closed
jonathansimmons opened this Issue Oct 25, 2015 · 15 comments

Comments

Projects
None yet
@jonathansimmons

jonathansimmons commented Oct 25, 2015

I've been trying to get a basic provider/ client setup running for a couple days now. Yet no matter what I do my client app is getting an invalid_grant error.

I've combed through the repo to better understand what would cause and invalid_grant error and it seems it should only be fired if the access_grant has been revoked.

When my client application fails due to the invalid_grant error devise is properly displaying the "invalid credentials error. When I check the db there is an unused access_grant. If grab the access_grants's token and use a ruby console everything works fine.

Example:

Loading development environment (Rails 4.2.4)
[1] pry(main)> callback = "http://localhost:3001/users/auth/doorkeeper/callback"
=> "http://localhost:3001/users/auth/doorkeeper/callback"
[2] pry(main)> app_id = "867e46cc052aafc5c580d328daa475d7024328df71eedfe3d640e197f651f0ed"
=> "867e46cc052aafc5c580d328daa475d7024328df71eedfe3d640e197f651f0ed"
[3] pry(main)> secret = "857c7e1f887d52064703ef19852032729e321643ab4638d302ab33eb0afe1a57"
=> "857c7e1f887d52064703ef19852032729e321643ab4638d302ab33eb0afe1a57"
[4] pry(main)> client = OAuth2::Client.new(app_id, secret, site: "http://localhost:3000")
=> #<OAuth2::Client:0x007f94d01fb0c8
 @id="867e46cc052aafc5c580d328daa475d7024328df71eedfe3d640e197f651f0ed",
 @options={:authorize_url=>"/oauth/authorize", :token_url=>"/oauth/token", :token_method=>:post, :connection_opts=>{}, :connection_build=>nil, :max_redirects=>5, :raise_errors=>true},
 @secret="857c7e1f887d52064703ef19852032729e321643ab4638d302ab33eb0afe1a57",
 @site="http://localhost:3000">
[5] pry(main)> client.auth_code.authorize_url(redirect_uri: callback)
=> "http://localhost:3000/oauth/authorize?client_id=867e46cc052aafc5c580d328daa475d7024328df71eedfe3d640e197f651f0ed&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fusers%2Fauth%2Fdoorkeeper%2Fcallback&response_type=code"

The resulting url will fail to authenticate and return {"error":"invalid_grant","error_description":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."}

So I go to the database and grab the unused access grant token and continue. NOTE: At this point and time the access grant token revoked_at is still NULL

[6] pry(main)> access_grant_token = "fe0d66bb2d5445f19337ac15f6973a6042b45055bc5973faa9d9820d95f49464"
=> "fe0d66bb2d5445f19337ac15f6973a6042b45055bc5973faa9d9820d95f49464"
[7] pry(main)> access = client.auth_code.get_token(access_grant_token, redirect_uri: callback)
=> #<OAuth2::AccessToken:0x007f94cf7482e8
 @client=
  #<OAuth2::Client:0x007f94d01fb0c8
   @auth_code=#<OAuth2::Strategy::AuthCode:0x007f94cfba3338 @client=#<OAuth2::Client:0x007f94d01fb0c8 ...>>,
   @connection=
    #<Faraday::Connection:0x007f94cfba3158
     @builder=
      #<Faraday::RackBuilder:0x007f94cfba2dc0
       @app=
        #<Faraday::Request::UrlEncoded:0x007f94d0960228
         @app=
          #<Faraday::Adapter::NetHttp:0x007f94d09602a0 @app=#<Proc:0x007f94d0960390@/Users/jonathan/.rvm/gems/ruby-2.2.2/gems/faraday-0.9.2/lib/faraday/rack_builder.rb:152 (lambda)>>>,
       @handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]>,
     @default_parallel_manager=nil,
     @headers={"User-Agent"=>"Faraday v0.9.2"},
     @options=#<struct Faraday::RequestOptions params_encoder=nil, proxy=nil, bind=nil, timeout=nil, open_timeout=nil, boundary=nil, oauth=nil>,
     @parallel_manager=nil,
     @params={},
     @proxy=nil,
     @ssl=
      #<struct Faraday::SSLOptions
       verify=nil,
       ca_file=nil,
       ca_path=nil,
       verify_mode=nil,
       cert_store=nil,
       client_cert=nil,
       client_key=nil,
       certificate=nil,
       private_key=nil,
       verify_depth=nil,
       version=nil>,
     @url_prefix=#<URI::HTTP http://localhost:3000/>>,
   @id="867e46cc052aafc5c580d328daa475d7024328df71eedfe3d640e197f651f0ed",
   @options={:authorize_url=>"/oauth/authorize", :token_url=>"/oauth/token", :token_method=>:post, :connection_opts=>{}, :connection_build=>nil, :max_redirects=>5, :raise_errors=>true},
   @secret="857c7e1f887d52064703ef19852032729e321643ab4638d302ab33eb0afe1a57",
   @site="http://localhost:3000">,
 @expires_at=1445794685,
 @expires_in=7200,
 @options={:mode=>:header, :header_format=>"Bearer %s", :param_name=>"access_token"},
 @params={"token_type"=>"bearer", "scope"=>"user", "created_at"=>1445787485},
 @refresh_token=nil,
 @token="00c560260d550167c871ecf89567d9a07e826e896072ae1a209960e0fe182b93">
[8] pry(main)> access.get("/me").parsed
=> {"id"=>1, "email"=>"jonathan.simmons@mac.com", "created_at"=>"2015-10-23T04:20:30.871Z", "updated_at"=>"2015-10-25T04:19:20.137Z"}

What am I doing wrong here? Why does my client constantly return and invalid grant_error.

@jonathansimmons

This comment has been minimized.

Show comment
Hide comment
@jonathansimmons

jonathansimmons Oct 26, 2015

So after vendoring the gem locally and putting adding ruby puts entries everywhere to track the sequence of events, it turns out the authorization is failing because of this rediret_url validation

So I modified the to see exactly what was going on like so:

# my modified method
def validate_redirect_uri
  puts "client redirect url is: #{redirect_uri}"
  puts "grant redirect uri is: #{grant.redirect_uri}"
  grant.redirect_uri == redirect_uri
end

# which outputs
client redirect uri is: http://localhost:3001/users/auth/doorkeeper/callback?code=dcf15a0e87ae6b168b4ae3ec5d840fb4e2acb62146b8b06a9a2005d3ce2a6467&state=cb154ebce1b3f7f42547d867c25ec0650579a3b7be3adc01
grant redirect uri is: redirect_uri: http://localhost:3001/users/auth/doorkeeper/callback

So the urls are different, but of course they are the client redirect_uri won't have the code and state since those are dynamic attributes.. right?

How did this ever work?

jonathansimmons commented Oct 26, 2015

So after vendoring the gem locally and putting adding ruby puts entries everywhere to track the sequence of events, it turns out the authorization is failing because of this rediret_url validation

So I modified the to see exactly what was going on like so:

# my modified method
def validate_redirect_uri
  puts "client redirect url is: #{redirect_uri}"
  puts "grant redirect uri is: #{grant.redirect_uri}"
  grant.redirect_uri == redirect_uri
end

# which outputs
client redirect uri is: http://localhost:3001/users/auth/doorkeeper/callback?code=dcf15a0e87ae6b168b4ae3ec5d840fb4e2acb62146b8b06a9a2005d3ce2a6467&state=cb154ebce1b3f7f42547d867c25ec0650579a3b7be3adc01
grant redirect uri is: redirect_uri: http://localhost:3001/users/auth/doorkeeper/callback

So the urls are different, but of course they are the client redirect_uri won't have the code and state since those are dynamic attributes.. right?

How did this ever work?

@jonathansimmons

This comment has been minimized.

Show comment
Hide comment
@jonathansimmons

jonathansimmons Oct 26, 2015

My problem seems similar to this issue in the Omniauth-Facebook repo. mkdynamic/omniauth-facebook#220

It looks as if the strategy in the client-app is what defines the callback url. So maybe there is something wrong with mine?

# lib/omniauth/strategies/doorkeeper.rb
module OmniAuth
  module Strategies
    class Doorkeeper < OmniAuth::Strategies::OAuth2
      option :name, :doorkeeper

      option :client_options, {
        site: 'http://localhost:3000',
        authorize_path: 'oauth/authorize'
      }

      uid do
        raw_info['id']
      end

      info do
        {
          :email => raw_info['email']
        }
      end

      def raw_info
        @raw_info ||= access_token.get('/me').parsed
      end
    end
  end
end

Could this issue somehow be a problem with devise?

jonathansimmons commented Oct 26, 2015

My problem seems similar to this issue in the Omniauth-Facebook repo. mkdynamic/omniauth-facebook#220

It looks as if the strategy in the client-app is what defines the callback url. So maybe there is something wrong with mine?

# lib/omniauth/strategies/doorkeeper.rb
module OmniAuth
  module Strategies
    class Doorkeeper < OmniAuth::Strategies::OAuth2
      option :name, :doorkeeper

      option :client_options, {
        site: 'http://localhost:3000',
        authorize_path: 'oauth/authorize'
      }

      uid do
        raw_info['id']
      end

      info do
        {
          :email => raw_info['email']
        }
      end

      def raw_info
        @raw_info ||= access_token.get('/me').parsed
      end
    end
  end
end

Could this issue somehow be a problem with devise?

@jonathansimmons

This comment has been minimized.

Show comment
Hide comment
@jonathansimmons

jonathansimmons Oct 26, 2015

So after days of frustration It turns out this was all because of a change in the omniauth-oauth2 repo

This issue reports the problem. The fix is to just roll back to 1.3.1 or override the callback_url method in your strategy.

jonathansimmons commented Oct 26, 2015

So after days of frustration It turns out this was all because of a change in the omniauth-oauth2 repo

This issue reports the problem. The fix is to just roll back to 1.3.1 or override the callback_url method in your strategy.

@rjayroach

This comment has been minimized.

Show comment
Hide comment
@rjayroach

rjayroach Nov 16, 2015

@jonathansimmons Thanks so much for posting your results here! This was driving me nuts for almost an hour..

rjayroach commented Nov 16, 2015

@jonathansimmons Thanks so much for posting your results here! This was driving me nuts for almost an hour..

@jonathansimmons

This comment has been minimized.

Show comment
Hide comment
@jonathansimmons

jonathansimmons commented Nov 16, 2015

@rjayroach 👍

@amedrz

This comment has been minimized.

Show comment
Hide comment
@amedrz

amedrz Dec 8, 2015

Really appreciate you posting your debugging here! @jonathansimmons

amedrz commented Dec 8, 2015

Really appreciate you posting your debugging here! @jonathansimmons

@lukkor

This comment has been minimized.

Show comment
Hide comment
@lukkor

lukkor Dec 22, 2015

@jonathansimmons Thanks, really help me! 👍

lukkor commented Dec 22, 2015

@jonathansimmons Thanks, really help me! 👍

@plrthink

This comment has been minimized.

Show comment
Hide comment
@plrthink

plrthink commented Jan 6, 2016

@niuage

This comment has been minimized.

Show comment
Hide comment
@niuage

niuage commented Jan 14, 2016

@jonathansimmons thanks a lot 🐸

@mcmire

This comment has been minimized.

Show comment
Hide comment
@mcmire

mcmire Jan 25, 2016

Thanks for your notes on this, this was really helpful.

It makes me sad that this still hasn't been fixed in omniauth-oauth2.

mcmire commented Jan 25, 2016

Thanks for your notes on this, this was really helpful.

It makes me sad that this still hasn't been fixed in omniauth-oauth2.

@gupta-ankit

This comment has been minimized.

Show comment
Hide comment
@gupta-ankit

gupta-ankit Jan 29, 2016

Thank you so much. I spent almost two days checking all parts of my doorkeeper provider and client to see what was wrong. Why did all of it suddenly stop working.

Thank you so much. I reverted the gem version and it all started working again. :)

gupta-ankit commented Jan 29, 2016

Thank you so much. I spent almost two days checking all parts of my doorkeeper provider and client to see what was wrong. Why did all of it suddenly stop working.

Thank you so much. I reverted the gem version and it all started working again. :)

@PENGZhaoqing

This comment has been minimized.

Show comment
Hide comment
@PENGZhaoqing

PENGZhaoqing Mar 19, 2016

Thanks for notes of this, I solved the same problem @jonathansimmons

PENGZhaoqing commented Mar 19, 2016

Thanks for notes of this, I solved the same problem @jonathansimmons

@nomes

This comment has been minimized.

Show comment
Hide comment
@nomes

nomes Mar 29, 2016

Thank you so much for working through this bug here. I got to the omniauth downgrade as a result of it. Thanks.

nomes commented Mar 29, 2016

Thank you so much for working through this bug here. I got to the omniauth downgrade as a result of it. Thanks.

@igorrfc

This comment has been minimized.

Show comment
Hide comment
@igorrfc

igorrfc May 2, 2016

Still dont working for me =/
even after the downgrade. Any other solution, folks?

igorrfc commented May 2, 2016

Still dont working for me =/
even after the downgrade. Any other solution, folks?

@LucasCioffi

This comment has been minimized.

Show comment
Hide comment
@LucasCioffi

LucasCioffi Jun 1, 2016

@igorrfc I made a local copy of the Doorkeeper gem, version 3.1.0. In Doorkeeper::Server I added the second line below to overwrite the redirect_uri.

def parameters
  context.request.parameters['redirect_uri'] = context.request.parameters['redirect_uri'].split("?")[0]
  context.request.parameters
end

This made the problem go away because (as @jonathansimmons points out), the redirect_uri sometimes had extra parameters at the end such as this:

?code=dcf15a0e87ae6b168b4ae3ec5d840fb4e2acb62146b8b06a9a2005d3ce2a6467&state=cb154ebce1b3f7f42547d867c25ec0650579a3b7be3adc01

I ended not doing this in production and rolling back to a previous version of the gem as suggested above, because it's not clear to me what those extra parameters are used for.

LucasCioffi commented Jun 1, 2016

@igorrfc I made a local copy of the Doorkeeper gem, version 3.1.0. In Doorkeeper::Server I added the second line below to overwrite the redirect_uri.

def parameters
  context.request.parameters['redirect_uri'] = context.request.parameters['redirect_uri'].split("?")[0]
  context.request.parameters
end

This made the problem go away because (as @jonathansimmons points out), the redirect_uri sometimes had extra parameters at the end such as this:

?code=dcf15a0e87ae6b168b4ae3ec5d840fb4e2acb62146b8b06a9a2005d3ce2a6467&state=cb154ebce1b3f7f42547d867c25ec0650579a3b7be3adc01

I ended not doing this in production and rolling back to a previous version of the gem as suggested above, because it's not clear to me what those extra parameters are used for.

bjelline added a commit to backend-development/rails_websockets that referenced this issue Jan 25, 2017

jrhee17 added a commit to jrhee17/exaka-omniauth that referenced this issue Dec 29, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment