Skip to content

Commit

Permalink
Merge pull request #1726 from doorkeeper-gem/fixes/fix-token-introspe…
Browse files Browse the repository at this point in the history
…ction

Refactor token introspection
  • Loading branch information
nbulaj authored Aug 13, 2024
2 parents ef629da + 544d131 commit bafdf78
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Add your entry here.
- [#1715] Fix token introspection invalid request reason
- [#1714] Fix `Doorkeeper::AccessToken.find_or_create_for` with empty scopes which raises NoMethodError
- [#1712] Add `Pragma: no-cache` to token response
- [#1726] Refactor token introspection class.

## 5.7.1

Expand Down
2 changes: 1 addition & 1 deletion lib/doorkeeper/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ def configure_secrets_for(type, using:, fallback:)
default: (lambda do |token, authorized_client, authorized_token|
if authorized_token
authorized_token.application == token&.application
elsif token.application
elsif token&.application
authorized_client == token.application
else
true
Expand Down
43 changes: 28 additions & 15 deletions lib/doorkeeper/oauth/token_introspection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ module OAuth
#
# @see https://datatracker.ietf.org/doc/html/rfc7662
class TokenIntrospection
attr_reader :error, :invalid_request_reason
attr_reader :token, :error, :invalid_request_reason

def initialize(server, token)
@server = server
@token = token

authorize!
end

def authorized?
authorize!
@error.blank?
end

Expand All @@ -37,7 +36,7 @@ def to_json(*)

private

attr_reader :server, :token
attr_reader :server

# If the protected resource uses OAuth 2.0 client credentials to
# authenticate to the introspection endpoint and its credentials are
Expand All @@ -59,24 +58,38 @@ def to_json(*)
def authorize!
# Requested client authorization
if server.credentials
@error = Errors::InvalidClient unless authorized_client
authorize_using_basic_auth!
elsif authorized_token
# Requested bearer token authorization
#
# If the protected resource uses an OAuth 2.0 bearer token to authorize
# its call to the introspection endpoint and the token used for
# authorization does not contain sufficient privileges or is otherwise
# invalid for this request, the authorization server responds with an
# HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
# Usage [RFC6750].
#
@error = Errors::InvalidToken unless valid_authorized_token?
authorize_using_bearer_token!
else
@error = Errors::InvalidRequest
@invalid_request_reason = :request_not_authorized
end
end

def authorize_using_basic_auth!
# Note that a properly formed and authorized query for an inactive or
# otherwise invalid token (or a token the protected resource is not
# allowed to know about) is not considered an error response by this
# specification. In these cases, the authorization server MUST instead
# respond with an introspection response with the "active" field set to
# "false" as described in Section 2.2.
@error = Errors::InvalidClient unless authorized_client
end

def authorize_using_bearer_token!
# Requested bearer token authorization
#
# If the protected resource uses an OAuth 2.0 bearer token to authorize
# its call to the introspection endpoint and the token used for
# authorization does not contain sufficient privileges or is otherwise
# invalid for this request, the authorization server responds with an
# HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
# Usage [RFC6750].
#
@error = Errors::InvalidToken unless valid_authorized_token?
end

# Client Authentication
def authorized_client
@authorized_client ||= server.credentials && server.client
Expand Down
12 changes: 11 additions & 1 deletion spec/controllers/tokens_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
end
end

it "responds with invalid_token error" do
it "responds with invalid_token error for bearer auth" do
request.headers["Authorization"] = "Bearer #{access_token.token}"

post :introspect, params: { token: token_for_introspection.token }
Expand All @@ -282,6 +282,16 @@
expect(json_response).not_to include("active")
expect(json_response).to include("error" => "invalid_token")
end

it "responds with access_denied error for basic auth" do
request.headers["Authorization"] = basic_auth_header_for_client(client)

post :introspect, params: { token: token_for_introspection.token }

response_status_should_be 200

expect(json_response).to include("active" => false)
end
end

context "when custom introspection response configured" do
Expand Down

0 comments on commit bafdf78

Please sign in to comment.