doorkeeper-gem/doorkeeper

Issue with defining application_class in Doorkeeper config causing NoMethodError

giovannelli opened this issue · 0 comments

Issue

When defining the application_class in the Doorkeeper configuration, an error is encountered:

NoMethodError:
        undefined method `application' for #<Doorkeeper::Application id:...

The issue arises in the AuthorizationCodeRequest during the execution of the before_successful_response method.

def before_successful_response
  grant.transaction do
    grant.lock!
    raise Errors::InvalidGrantReuse if grant.revoked?

    grant.revoke

    find_or_create_access_token(
      grant.application,
      resource_owner,
      grant.scopes,
      custom_token_attributes_with_data,
      server,
    )
  end

  super
end

The problem appears to stem from the following code block in the base_request:

application = client.is_a?(Doorkeeper.config.application_model) ? client : client&.application

In certain cases, such as the one presented, this check fails to work as intended because the client instance is of type Doorkeeper::Application. This is due to the behavior of grant.application returning a Doorkeeper::Application instance instead of Doorkeeper.config.application_class.to_s, despite the AccessGrant relationship being correctly defined as shown below:

belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
                         optional: true,
                         inverse_of: :access_grants

To address this issue, a potential solution is to modify the AuthorizationCodeRequest.before_successful_response method as follows:

def before_successful_response
  grant.transaction do
    grant.lock!
    raise Errors::InvalidGrantReuse if grant.revoked?

    grant.revoke

    find_or_create_access_token(
      client,
      resource_owner,
      grant.scopes,
      custom_token_attributes_with_data,
      server,
    )
  end

  super
end

By passing client directly, similar to how it's done for other types of requests, the issue might be resolved.

Please share your thoughts on whether the proposed solution appears reasonable or if there are any crucial aspects that I may have overlooked.

System configuration

Doorkeeper Version: latest
Ruby Version: 3.2.2
Rails Version: 7.0.7.2

Doorkeeper initializer:

# config/initializers/doorkeeper.rb
Doorkeeper.configure do
    orm :active_record

    custom_access_token_expires_in { |context| context.client.expires_in }

    application_class "Application"
    access_token_class "AccessToken"
    access_token_generator "TokenEncoder"
    api_only
    base_controller "ActionController::API"
    allow_token_introspection do |token, authorized_client, authorized_token|
      [token&.application&.id, authorized_token&.application&.id].include?(authorized_client.id)
    end

    reuse_access_token
    use_refresh_token
    access_token_methods :from_bearer_authorization
    grant_flows %w[authorization_code password client_credentials].freeze
    realm REALM
  end