HTTPBadRequest {" error_description ": "代码已经过期"," error ": " invalid_grant "}用于Oauth认证,Ruby on Rails

时间:2022-08-11 15:47:21

I am having weird behavior of my omniauth app. Basically, I have admin panel to whom access it is required to authenticate with Yandex account.

我的omniauth应用程序有奇怪的行为。基本上,我有管理员面板,需要通过Yandex账户对其进行认证。

Problem: I did everything as required in multiple guides and everything worked fine since yesterday I tried to authenticate with Yandex account and I received HTTPBadRequest error.

问题:从昨天开始,我尝试使用Yandex账户进行认证,并收到了HTTPBadRequest错误。

Note: I haven't changed a bit in my code. All my access data client_Id and password hasn't changed either.

注意:我的代码没有做任何修改。我的所有访问数据client_Id和密码都没有改变。

Gemfile:

Gemfile:

gem "omniauth-yandex"

Routes:

路线:

devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }

CallbacksController:

CallbacksController:

def yandex
    require 'net/http'
    require 'json'  # => false

    @user = User.from_omniauth(request.env["omniauth.auth"])

    @client_id = Rails.application.secrets.client_id 
    @secret =  Rails.application.secrets.password
    @authorization_code = params[:code]

    @user.update_attribute(:code, @authorization_code)
    @user.update_attribute(:state, params[:state])


    @post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"

    @url = "https://oauth.yandex.ru/token"

    url = URI.parse(@url)
    req = Net::HTTP::Post.new(url.request_uri)
    req['host'] ="oauth.yandex.ru"
    req['Content-Length'] = @post_body.length
    req['Content-Type'] = 'application/x-www-form-urlencoded'
    req.body = @post_body
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = (url.scheme == "https")

    @response_mess = http.request(req)

    refreshhash = JSON.parse(@response_mess.body)
    access_token  = refreshhash['access_token']
    refresh_token  = refreshhash['refresh_token']
    access_token_expires_at = DateTime.now + refreshhash["expires_in"].to_i.seconds


    if access_token.present? && refresh_token.present? && access_token_expires_at.present?
        @user.update_attribute(:access_token, access_token)
        @user.update_attribute(:refresh_token, refresh_token)
        @user.update_attribute(:expires_in, access_token_expires_at)

        sign_in(@user)
        redirect_to admin_dashboard_index_path
    end

end

User model:

用户模式:

    require 'rest-client'

      devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :trackable, :validatable,
          :omniauthable, :omniauth_providers => [:yandex]

      def self.from_omniauth(auth)
          where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
            user.provider = auth.provider
            user.uid = auth.uid
            user.email =  auth.info.email
            user.code = auth.info.code
            user.state = auth.info.state
            user.password = Devise.friendly_token[0,20]
          end
      end

      def refresh_token_if_expired
          if token_expired?
            response    = RestClient.post "https://oauth.yandex.com/token",
            :grant_type => 'refresh_token',
            :refresh_token => self.refresh_token

            refreshhash = JSON.parse(response.body)

            self.access_token     = refreshhash['access_token']
            self.expires_in = DateTime.now + refreshhash["expires_in"].to_i.seconds

            self.save

            puts 'Saved'
          end
      end

      def token_expired?          
          expiry = Time.at(self.expires_in)
          logger.debug "#{expiry}"
          return true if expiry < Time.now 
          token_expires_at = expiry
          save if changed?
          false 
      end
  end

Problem:

问题:

HTTPBadRequest error highlights the line in CallbacksController:

HTTPBadRequest错误突出显示了CallbacksController中的一行:

@response_mess = http.request(req)

What I have tried:

我已经尝试:

1) Restarted Rails app;

1)重新启动Rails应用程序;

2) Deleted user from database and tried to sign in again;

2)从数据库中删除用户,尝试再次登录;

3) Deleted registered app in Yandex Oauth section. Then added back again with new client_id and password.

3)删除Yandex Oauth区注册app然后再次添加新client_id和密码。

From Yandex Oauth guide:

从Yandex Oauth指南:

Exchanging an authorization code for a token

The application sends the code, along with its ID and password, in a POST request.
POST /token HTTP/1.1
Host: oauth.yandex.
Content-type: application/x-www-form-urlencoded
Content-Length: <length of request body>
[Authorization: Basic <encoded client_id:client_secret string>]

   grant_type=authorization_code
 & code=<authorization code>
[& client_id=<application ID>]
[& client_secret=<application password>]
[& device_id=<device ID>]
[& device_name=<device name>]

UPDATE: I am receiving this error:

更新:我收到这个错误:

{"error_description": "Code has expired", "error": "invalid_grant"}

UPDATE 2 : I tried to contact Yandex Support. I sent them brief description to my problem and link to question. But no response.

更新2:我试图联系Yandex Support。我给他们简单的描述我的问题和链接到问题。但没有回应。

UPDATE 3:

更新3:

I tried the same POST request in CHROME POSTMAN and received the same response as

我在CHROME POSTMAN中尝试了相同的POST请求,并收到了相同的响应。

{"error_description": "Code has expired", "error": "invalid_grant"}

{"error_description": "代码已过期","error": "invalid_grant"}

Update 4:

更新4:

I checked again all my credentials client_id and password for Yandex and they are 100% valid.

我再次检查了Yandex的所有凭证client_id和密码,它们是100%有效的。

1 个解决方案

#1


3  

From the OAUTH 2.0 RFC:

OAUTH 2.0 RFC:

invalid_grant
    The provided authorization grant (e.g., authorization
    code, resource owner credentials) or refresh token is
    invalid, expired, revoked, does not match the redirection
    URI used in the authorization request, or was issued to
    another client.

This is further explained on the Yandex site:

这在Yandex网站上有进一步解释:

The access_token could not be issued. Either the temporary authorization code was not issued by Yandex.Money, or it has expired, or an access_token has already been issued for this temporary authorization code (a duplicate request for an access token using the same temporary authorization code).

无法发出access_token。要么是Yandex没有发布临时授权码。货币,或者它已经过期,或者这个临时授权代码已经发出了access_token(使用相同的临时授权代码对访问令牌的重复请求)。

You are supplying invalid credentials to Yandex. Forget the code you've written for a moment because the only part that is failing is when it sends the data to Yandex. Yandex is telling you the data is invalid and you have confirmed this with Postman. That means this is sending invalid data:

你向Yandex提供无效凭证。暂时忘记您所编写的代码,因为惟一失败的部分是当它将数据发送到Yandex时。Yandex告诉你数据无效,你已经和邮递员确认了。这意味着这是在发送无效数据:

@post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"

So double check these things:

仔细检查一下

  1. Is the grant_type supposed to be authorization_code?
  2. grant_type应该是authorization_code吗?
  3. Are you certain @authorization_code is set to a value (and not nil) and that the value is valid?
  4. 您确定@authorization_code被设置为一个值(而不是nil),并且该值是有效的吗?
  5. Same question for @client_id?
  6. @client_id同样的问题吗?
  7. Same question @secret?
  8. 同样的问题@secret吗?
  9. Are you missing a redirect_uri value?
  10. 您是否缺少一个redirect_uri值?

#1


3  

From the OAUTH 2.0 RFC:

OAUTH 2.0 RFC:

invalid_grant
    The provided authorization grant (e.g., authorization
    code, resource owner credentials) or refresh token is
    invalid, expired, revoked, does not match the redirection
    URI used in the authorization request, or was issued to
    another client.

This is further explained on the Yandex site:

这在Yandex网站上有进一步解释:

The access_token could not be issued. Either the temporary authorization code was not issued by Yandex.Money, or it has expired, or an access_token has already been issued for this temporary authorization code (a duplicate request for an access token using the same temporary authorization code).

无法发出access_token。要么是Yandex没有发布临时授权码。货币,或者它已经过期,或者这个临时授权代码已经发出了access_token(使用相同的临时授权代码对访问令牌的重复请求)。

You are supplying invalid credentials to Yandex. Forget the code you've written for a moment because the only part that is failing is when it sends the data to Yandex. Yandex is telling you the data is invalid and you have confirmed this with Postman. That means this is sending invalid data:

你向Yandex提供无效凭证。暂时忘记您所编写的代码,因为惟一失败的部分是当它将数据发送到Yandex时。Yandex告诉你数据无效,你已经和邮递员确认了。这意味着这是在发送无效数据:

@post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"

So double check these things:

仔细检查一下

  1. Is the grant_type supposed to be authorization_code?
  2. grant_type应该是authorization_code吗?
  3. Are you certain @authorization_code is set to a value (and not nil) and that the value is valid?
  4. 您确定@authorization_code被设置为一个值(而不是nil),并且该值是有效的吗?
  5. Same question for @client_id?
  6. @client_id同样的问题吗?
  7. Same question @secret?
  8. 同样的问题@secret吗?
  9. Are you missing a redirect_uri value?
  10. 您是否缺少一个redirect_uri值?