Class: SimpleOAuth::OAuth2::AuthorizationResponse

Inherits:
Object
  • Object
show all
Defined in:
lib/simple_oauth/oauth2/authorization_response.rb,
sig/simple_oauth/oauth2.rbs

Overview

The response an authorization server returns to a client's redirect URI

Constant Summary collapse

STATE_MISMATCH =

The description of a response whose state is not the one the request sent

Returns:

  • (String)
"The authorization response answers a different request"
ISSUER_MISMATCH =

The description of a response from an authorization server other than the expected one

Returns:

  • (String)
"The authorization response is from a different authorization server"
NO_CODE =

The description of a response carrying neither a code nor an error

Returns:

  • (String)
"The authorization response has no code"
DUPLICATE_PARAMETER =

The description of a response that repeats a parameter, which RFC 6749 Section 3.1 forbids

Returns:

  • (String)
"The authorization response repeats a parameter"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ AuthorizationResponse

Initialize a response from the parameters of an authorization response

Examples:

SimpleOAuth::OAuth2::AuthorizationResponse.new({"code" => "abc", "state" => "xyz"})

Parameters:

  • params (Hash)

    the response parameters

Raises:

  • (KeyError)

    if the parameters have no code



153
154
155
156
157
158
159
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 153

def initialize(params)
  @params = params.transform_keys(&:to_s).freeze
  @code = @params.fetch("code")
  @state = @params["state"]
  @issuer = @params["iss"]
  freeze
end

Instance Attribute Details

#codeString (readonly)

The authorization code, to exchange for a token

Examples:

response.code # => "SplxlOBeZQQYbYS6WxSbIA"

Returns:

  • (String)

    the authorization code



40
41
42
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 40

def code
  @code
end

#issuerString? (readonly)

The issuer the authorization server identified itself with (RFC 9207)

Examples:

response.issuer # => "https://server.example.com"

Returns:

  • (String, nil)

    the issuer



56
57
58
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 56

def issuer
  @issuer
end

#paramsHash{String => String} (readonly)

Every parameter of the authorization response

Examples:

response.params["code"] # => "SplxlOBeZQQYbYS6WxSbIA"

Returns:

  • (Hash{String => String})

    the parameters



64
65
66
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 64

def params
  @params
end

#stateString? (readonly)

The state the authorization server returned

Examples:

response.state # => "xyz"

Returns:

  • (String, nil)

    the state



48
49
50
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 48

def state
  @state
end

Class Method Details

.matches?(expected, actual) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Whether the response carries what the client expected, in constant time

Examples:

SimpleOAuth::OAuth2::AuthorizationResponse.matches?("xyz", "xyz") # => true

Parameters:

  • expected (String, nil)

    what the client expects, or nil to expect anything

  • actual (String, nil)

    what the response carried

Returns:

  • (Boolean)

    true if the response is acceptable



140
141
142
143
144
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 140

def self.matches?(expected, actual)
  return true if expected.nil?

  !actual.nil? && OpenSSL.secure_compare(expected, actual)
end

.mismatch_reason(params, state, issuer) ⇒ String?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The reason a response cannot be trusted or used, if there is one

Examples:

SimpleOAuth::OAuth2::AuthorizationResponse.mismatch_reason({"code" => "a"}, nil, nil) # => nil

Parameters:

  • params (Hash)

    the response parameters

  • state (String, nil)

    the state the request sent

  • issuer (String, nil)

    the expected issuer

Returns:

  • (String, nil)

    the reason, or nil if the response is usable



125
126
127
128
129
130
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 125

def self.mismatch_reason(params, state, issuer)
  return STATE_MISMATCH unless matches?(state, params["state"])
  return ISSUER_MISMATCH unless matches?(issuer, params["iss"])

  NO_CODE if params["code"].to_s.empty?
end

.parameters(query) ⇒ Hash{String => String}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The parameters of an authorization response

Examples:

SimpleOAuth::OAuth2::AuthorizationResponse.parameters("code=abc") # => {"code" => "abc"}

Parameters:

  • query (String, Hash, nil)

    the query string of the redirect, or its parsed parameters

Returns:

  • (Hash{String => String})

    the parameters

Raises:

  • (Error)

    if a parameter is repeated, which RFC 6749 Section 3.1 forbids



96
97
98
99
100
101
102
103
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 96

def self.parameters(query)
  return query.transform_keys(&:to_s) if query.is_a?(Hash)

  pairs = URI.decode_www_form(query.to_s)
  raise Error.new(code: nil, description: DUPLICATE_PARAMETER) if pairs.length > pairs.uniq(&:first).length

  pairs.to_h
end

.parse(query, state: nil, issuer: nil) ⇒ AuthorizationResponse

Parse an authorization response, raising unless the client can trust and use it

Examples:

SimpleOAuth::OAuth2::AuthorizationResponse.parse("code=abc&state=xyz", state: "xyz")

Parameters:

  • query (String, Hash, nil)

    the query string of the redirect, or its parsed parameters

  • state (String, nil) (defaults to: nil)

    the state the authorization URL sent, which the response must carry; nil to make no such check, for a request that sent none

  • issuer (String, nil) (defaults to: nil)

    the issuer the server must identify itself with; nil to make no such check

  • state: (String, nil) (defaults to: nil)
  • issuer: (String, nil) (defaults to: nil)

Returns:

Raises:

  • (Error)

    if the server reported an error, or the response cannot be trusted



78
79
80
81
82
83
84
85
86
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 78

def self.parse(query, state: nil, issuer: nil)
  params = parameters(query)
  raise reported_error(params) if params.key?("error")

  reason = mismatch_reason(params, state, issuer)
  raise Error.new(code: nil, description: reason) if reason

  new(params)
end

.reported_error(params) ⇒ Error

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The error the authorization server reported (RFC 6749 Section 4.1.2.1)

Examples:

SimpleOAuth::OAuth2::AuthorizationResponse.reported_error({"error" => "access_denied"})

Parameters:

  • params (Hash)

    the response parameters

Returns:



112
113
114
# File 'lib/simple_oauth/oauth2/authorization_response.rb', line 112

def self.reported_error(params)
  Error.new(code: params["error"], description: params["error_description"], uri: params["error_uri"])
end