simple-oauth2/simple_oauth2

View on GitHub
lib/simple_oauth2/strategies/refresh_token.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Simple
  module OAuth2
    module Strategies
      # Refresh Token strategy class. Processes request and respond with Access Token.
      #
      # @see https://tools.ietf.org/html/rfc6749#section-6
      #
      # After an access token expires, using it to make a request from the API
      # will result in an "Invalid Token Error". At this point,
      # if a refresh token was included when the original access token was issued,
      # it can be used to request a fresh access token from the authorization server.
      #
      # Here is an example POST request, using a refresh token to obtain a new access token:
      #
      # @example
      #   https://api.todo.com/oauth/token?grant_type=refresh_token&    # REQUIRED
      #                                    client_id=CLIENT_ID&         # REQUIRED
      #                                    client_secret=CLIENT_SECRET& # REQUIRED
      #                                    refresh_token=REFRESH_TOKEN& # REQUIRED
      #                                    scope=read                   # OPTIONAL
      #
      class RefreshToken < Base
        class << self
          # Processes Refresh Token request.
          #
          # @param request [Rack::Request] request object.
          #
          # @return [Rack::OAuth2::AccessToken::Bearer] bearer token instance.
          #
          def process(request)
            client = token_verify_client!(request)
            refresh_token = verify_refresh_token!(request, client.id)

            token = config.access_token_class.create_for(
              client, refresh_token.resource_owner, scopes_from(request)
            )
            run_callback_on_refresh_token(refresh_token) if config.on_refresh_runnable?

            expose_to_bearer_token(token)
          end

          private

          # Check refresh token and client id for exact matching verifier
          def verify_refresh_token!(request, client_id)
            refresh_token = config.access_token_class.by_refresh_token(request.refresh_token)
            refresh_token || request.invalid_grant!
            refresh_token.client_id == client_id || request.unauthorized_client!

            refresh_token
          end

          # Invokes custom callback on Access Token refresh.
          # If callback is a proc, then call it with token.
          # If access token responds to callback value (symbol for example), then call it from the token.
          #
          # @param access_token [Object] Access Token instance
          #
          def run_callback_on_refresh_token(access_token)
            callback = config.on_refresh

            if callback.respond_to?(:call)
              callback.call(access_token)
            elsif access_token.respond_to?(callback)
              access_token.send(callback)
            else
              raise(ArgumentError, ":on_refresh is not a block and Access Token class doesn't respond to #{callback}!")
            end
          end
        end
      end
    end
  end
end