Auto-refresh OAuth 2 tokens & retry request on 401 response
This commit is contained in:
parent
1cf7975319
commit
3d157007f6
|
@ -5,6 +5,8 @@
|
||||||
* :api_method in request can no longer be a string
|
* :api_method in request can no longer be a string
|
||||||
* Deprecated ResumableUpload.send_* methods.
|
* Deprecated ResumableUpload.send_* methods.
|
||||||
* Reduce memory utilization when uploading large files
|
* Reduce memory utilization when uploading large files
|
||||||
|
* Automatic refresh of OAuth 2 credentials & retry of request when 401 errors
|
||||||
|
are returned
|
||||||
* Simplify internal request processing.
|
* Simplify internal request processing.
|
||||||
|
|
||||||
# 0.4.7
|
# 0.4.7
|
||||||
|
|
|
@ -540,6 +540,15 @@ module Google
|
||||||
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
|
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
|
||||||
|
|
||||||
result = request.send(connection)
|
result = request.send(connection)
|
||||||
|
if result.status == 401 && authorization.respond_to?(:refresh_token)
|
||||||
|
begin
|
||||||
|
authorization.fetch_access_token!
|
||||||
|
result = request.send(connection)
|
||||||
|
rescue Signet::AuthorizationError
|
||||||
|
# Ignore since we want the original error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
require 'jwt'
|
require 'jwt'
|
||||||
require 'signet/oauth_2/client'
|
require 'signet/oauth_2/client'
|
||||||
|
require 'delegate'
|
||||||
|
|
||||||
module Google
|
module Google
|
||||||
class APIClient
|
class APIClient
|
||||||
|
@ -117,7 +118,21 @@ module Google
|
||||||
authorization.grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
|
authorization.grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
|
||||||
authorization.extension_parameters = { :assertion => assertion }
|
authorization.extension_parameters = { :assertion => assertion }
|
||||||
authorization.fetch_access_token!(options)
|
authorization.fetch_access_token!(options)
|
||||||
return authorization
|
return JWTAuthorization.new(authorization, self, person)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class JWTAuthorization < DelegateClass(Signet::OAuth2::Client)
|
||||||
|
def initialize(authorization, asserter, person = nil)
|
||||||
|
@asserter = asserter
|
||||||
|
@person = person
|
||||||
|
super(authorization)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_access_token!(options={})
|
||||||
|
new_authorization = @asserter.authorize(@person, options)
|
||||||
|
__setobj__(new_authorization)
|
||||||
|
self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,5 +52,39 @@ describe Google::APIClient::JWTAsserter do
|
||||||
auth.access_token.should == "1/abcdef1234567890"
|
auth.access_token.should == "1/abcdef1234567890"
|
||||||
conn.verify
|
conn.verify
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'should be refreshable' do
|
||||||
|
conn = stub_connection do |stub|
|
||||||
|
stub.post('/o/oauth2/token') do |env|
|
||||||
|
params = Addressable::URI.form_unencode(env[:body])
|
||||||
|
JWT.decode(params.assoc("assertion").last, @key.public_key)
|
||||||
|
params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
|
||||||
|
[200, {}, '{
|
||||||
|
"access_token" : "1/abcdef1234567890",
|
||||||
|
"token_type" : "Bearer",
|
||||||
|
"expires_in" : 3600
|
||||||
|
}']
|
||||||
|
end
|
||||||
|
stub.post('/o/oauth2/token') do |env|
|
||||||
|
params = Addressable::URI.form_unencode(env[:body])
|
||||||
|
JWT.decode(params.assoc("assertion").last, @key.public_key)
|
||||||
|
params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
|
||||||
|
[200, {}, '{
|
||||||
|
"access_token" : "1/0987654321fedcba",
|
||||||
|
"token_type" : "Bearer",
|
||||||
|
"expires_in" : 3600
|
||||||
|
}']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
|
||||||
|
auth = asserter.authorize(nil, { :connection => conn })
|
||||||
|
auth.should_not == nil?
|
||||||
|
auth.access_token.should == "1/abcdef1234567890"
|
||||||
|
|
||||||
|
auth.fetch_access_token!(:connection => conn)
|
||||||
|
auth.access_token.should == "1/0987654321fedcba"
|
||||||
|
|
||||||
|
conn.verify
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue