diff --git a/lib/oauth2/access_token.rb b/lib/oauth2/access_token.rb index 2c152b89..14ca15bf 100644 --- a/lib/oauth2/access_token.rb +++ b/lib/oauth2/access_token.rb @@ -1,6 +1,6 @@ module OAuth2 class AccessToken - attr_reader :client, :token, :expires_in, :expires_at, :params + attr_reader :client, :token, :expires_in, :expires_at, :params, :time_skew attr_accessor :options, :refresh_token, :response class << self @@ -37,17 +37,27 @@ def from_kvform(client, kvform) # @option opts [String] :header_format ('Bearer %s') the string format to use for the Authorization header # @option opts [String] :param_name ('access_token') the parameter name to use for transmission of the # Access Token value in :body or :query transmission mode - def initialize(client, token, opts = {}) # rubocop:disable Metrics/AbcSize + def initialize(client, token, opts = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + local_now = Time.now.to_i + opts = opts.dup @client = client @token = token.to_s - opts = opts.dup + @time_skew = 0 + [:refresh_token, :expires_in, :expires_at].each do |arg| instance_variable_set("@#{arg}", opts.delete(arg) || opts.delete(arg.to_s)) end + @expires_in ||= opts.delete('expires') @expires_in &&= @expires_in.to_i @expires_at &&= @expires_at.to_i - @expires_at ||= Time.now.to_i + @expires_in if @expires_in + + if @expires_in + @expires_at ||= local_now + @expires_in + calculated_issued_at = @expires_at - @expires_in + @time_skew = local_now - calculated_issued_at + end + @options = {:mode => opts.delete(:mode) || :header, :header_format => opts.delete(:header_format) || 'Bearer %s', :param_name => opts.delete(:param_name) || 'access_token'} @@ -72,7 +82,7 @@ def expires? # # @return [Boolean] def expired? - expires? && (expires_at <= Time.now.to_i) + expires? && (expires_at + time_skew <= Time.now.to_i) end # Refreshes the current Access Token diff --git a/spec/oauth2/access_token_spec.rb b/spec/oauth2/access_token_spec.rb index 699b31d9..a6b8078c 100644 --- a/spec/oauth2/access_token_spec.rb +++ b/spec/oauth2/access_token_spec.rb @@ -151,6 +151,30 @@ def assert_initialized_token(target) # rubocop:disable Metrics/AbcSize allow(Time).to receive(:now).and_return(@now) expect(access).to be_expired end + + describe 'time skew' do + let(:time_skew) { 10 } + let(:expires_in) { 300 } + let(:expires_at) { Time.now.to_i - 10 + expires_in } + let!(:access) { described_class.new(client, token, :refresh_token => 'abaca', :expires_at => expires_at, :expires_in => expires_in) } + + context 'when not within time skew correction' do + let(:now) { Time.at(expires_at) + time_skew + 1 } + + it 'access is expired' do + allow(Time).to receive(:now).and_return(now) + expect(access).to be_expired + end + end + + context 'when within time skew correction' do + let(:now) { Time.at(expires_at) + time_skew - 1 } + + it 'access is not expired' do + expect(access).not_to be_expired + end + end + end end describe '#refresh' do