class Doorkeeper::OAuth::TokenIntrospection

@see datatracker.ietf.org/doc/html/rfc7662<br><br>RFC7662 OAuth 2.0 Token Introspection

def active?


be used at the resource server making the introspection call.
authorization server MUST determine whether or not the token can
o If the token can be used only at certain resource servers, the
validate the signature.
o If the token has been signed, the authorization server MUST
place.
server MUST determine whether or not such a revocation has taken
o If the token can be revoked after it was issued, the authorization
period has started yet.
authorization server MUST determine whether or not a token's valid
o If the token can be issued before it is able to be used, the
whether or not the token has expired.
o If the token can expire, the authorization server MUST determine

token's state. For instance, these tests include the following:
authorization server MUST perform all applicable checks against a
authorization server to determine the state of a token, the
Since resource servers using token introspection rely on the

* The token was issued to a different client than is making this request
* The token expired
* The token requested does not exist or is invalid

Any other error is considered an "inactive" token.

before its expiration time).
given time window of validity (e.g., after its issuance time and
has not been revoked by the resource owner, and is within its
that a given token has been issued by this authorization server,
value return for the "active" property will generally indicate
server and the information it keeps about its tokens, but a "true"
will vary depending on the implementation of the authorization
is currently active. The specifics of a token's "active" state
Boolean indicator of whether or not the presented token
def active?
  if authorized_client
    valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
  else
    valid_token?
  end
end

def authorize!

Other tags:
    See: https://www.oauth.com/oauth2-servers/token-introspection-endpoint/ -
def authorize!
  # Requested client authorization
  if server.credentials
    authorize_using_basic_auth!
  elsif authorized_token
    authorize_using_bearer_token!
  else
    @error = Errors::InvalidRequest
    @invalid_request_reason = :request_not_authorized
  end
end

def authorize_using_basic_auth!

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!

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

def authorized?

def authorized?
  authorize!
  @error.blank?
end

def authorized_client

Client Authentication
def authorized_client
  @authorized_client ||= server.credentials && server.client
end

def authorized_token

Bearer Token Authentication
def authorized_token
  @authorized_token ||= Doorkeeper.authenticate(server.context.request)
end

def authorized_token_matches_introspected?

RFC7662 Section 2.1
def authorized_token_matches_introspected?
  authorized_token.token == @token&.token
end

def customize_response(response)

Other tags:
    See: https://datatracker.ietf.org/doc/html/rfc7662#section-2.2 -
def customize_response(response)
  customized_response = Doorkeeper.config.custom_introspection_response.call(
    token,
    server.context,
  )
  return response if customized_response.blank?
  response.merge(customized_response)
end

def error_response

def error_response
  return if @error.blank?
  if @error == Errors::InvalidToken
    OAuth::InvalidTokenResponse.from_access_token(authorized_token)
  elsif @error == Errors::InvalidRequest
    OAuth::InvalidRequestResponse.from_request(self)
  else
    OAuth::ErrorResponse.from_request(self)
  end
end

def failure_response

Other tags:
    See: https://datatracker.ietf.org/doc/html/rfc7662 - 2.2. Introspection Response
def failure_response
  {
    active: false,
  }
end

def initialize(server, token)

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

def success_response

2.2. Introspection Response
def success_response
  customize_response(
    active: true,
    scope: @token.scopes_string,
    client_id: @token.try(:application).try(:uid),
    token_type: @token.token_type,
    exp: @token.expires_at.to_i,
    iat: @token.created_at.to_i,
  )
end

def to_json(*)

def to_json(*)
  active? ? success_response : failure_response
end

def token_introspection_allowed?(auth_client: nil, auth_token: nil)

Config constraints for introspection in Doorkeeper.config.allow_token_introspection
def token_introspection_allowed?(auth_client: nil, auth_token: nil)
  allow_introspection = Doorkeeper.config.allow_token_introspection
  return allow_introspection unless allow_introspection.respond_to?(:call)
  allow_introspection.call(@token, auth_client, auth_token)
end

def valid_authorized_token?

def valid_authorized_token?
  !authorized_token_matches_introspected? &&
    authorized_token.accessible? &&
    token_introspection_allowed?(auth_token: authorized_token)
end

def valid_token?

Token can be valid only if it is not expired or revoked.
def valid_token?
  @token&.accessible?
end