[英]HTTPBadRequest {“error_description”: “Code has expired”, “error”: “invalid_grant”} for Oauth authentification, Ruby on Rails
I am having weird behavior of my omniauth app. 我的omniauth应用程序有奇怪的行为。 Basically, I have admin panel to whom access it is required to authenticate with Yandex account. 基本上,我有管理员面板,需要访问它才能使用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. 3)在Yandex Oauth部分删除了注册的应用程序。 Then added back again with new client_id and password. 然后再添加新的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. 更新2 :我试图联系Yandex支持。 I sent them brief description to my problem and link to question. 我把简短的描述发给我的问题并链接到问题。 But no response. 但没有回应。
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”:“代码已过期”,“错误”:“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%有效。
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. 无法发出access_token。 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). 临时授权代码不是由Yandex.Money发布的,或者已经过期,或者已经为此临时授权代码发出了access_token(使用相同的临时授权代码对访问令牌的重复请求)。
You are supplying invalid credentials to Yandex. 您正在向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。 Yandex is telling you the data is invalid and you have confirmed this with Postman. Yandex告诉你数据无效,你已经向Postman证实了这一点。 That means this is sending invalid data: 这意味着这是发送无效数据:
@post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"
So double check these things: 所以仔细检查这些东西:
grant_type
supposed to be authorization_code
? grant_type
应该是authorization_code
吗? @authorization_code
is set to a value (and not nil) and that the value is valid? 你确定@authorization_code
被设置为一个值(而不是nil)并且该值是有效的吗? @client_id
? 同样的问题@client_id
? @secret
? 同样的问题@secret
? redirect_uri
value? 你错过了redirect_uri
值吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.