Class: SimpleOAuth::Header

Inherits:
Object
  • Object
show all
Extended by:
Encoding, ClassMethods
Defined in:
lib/simple_oauth/header.rb,
lib/simple_oauth/header/class_methods.rb,
sig/simple_oauth.rbs,
sig/simple_oauth/header/class_methods.rbs

Overview

Generates OAuth 1.0 Authorization headers for HTTP requests

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

OAUTH_SCHEME =

OAuth header scheme prefix

Returns:

  • (String)
"OAuth".freeze
OAUTH_PREFIX =

Prefix for OAuth parameters

Returns:

  • (String)
"oauth_".freeze
DEFAULT_SIGNATURE_METHOD =

Default signature method per RFC 5849

Returns:

  • (String)
"HMAC-SHA1".freeze
OAUTH_VERSION =

OAuth version

Returns:

  • (String)
"1.0".freeze
ATTRIBUTE_KEYS =

Valid OAuth attribute keys that can be included in the header

Returns:

  • (Array[Symbol])
%i[body_hash callback consumer_key nonce signature_method timestamp token verifier version].freeze
IGNORED_KEYS =

Keys that are used internally but should not appear in attributes

Returns:

  • (Array[Symbol])
%i[consumer_secret token_secret signature realm ignore_extra_keys].freeze
PARSE_KEYS =

Valid keys when parsing OAuth parameters (ATTRIBUTE_KEYS + signature)

Returns:

  • (Array[Symbol])
[*ATTRIBUTE_KEYS, :signature].freeze

Constants included from Encoding

Encoding::UNRESERVED_CHARS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ClassMethods

body_hash, default_options, encode_base64, generate_nonce, parse, parse_form_body

Methods included from Encoding

escape, unescape

Constructor Details

#initialize(method, url, params, oauth = {}, body = nil) ⇒ Header

Creates a new OAuth header

Parameters:

  • method (String, Symbol)
  • url (String, URI::Generic)
  • params (params_hash)
  • oauth (oauth_options, String) (defaults to: {})
  • body (String, nil) (defaults to: nil)


82
83
84
85
86
87
88
# File 'lib/simple_oauth/header.rb', line 82

def initialize(method, url, params, oauth = {}, body = nil)
  @method = method.to_s.upcase
  @uri = normalize_uri(url)
  @params = params
  @body = body
  @options = build_options(oauth, body)
end

Instance Attribute Details

#bodyString? (readonly)

The raw request body for oauth_body_hash computation

Returns:

  • (String, nil)


54
55
56
# File 'lib/simple_oauth/header.rb', line 54

def body
  @body
end

#methodString (readonly)

The HTTP method for the request

Returns:

  • (String)


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

def method
  @method
end

#optionsoauth_options (readonly)

The OAuth options including credentials and signature

Returns:

  • (oauth_options)


61
62
63
# File 'lib/simple_oauth/header.rb', line 61

def options
  @options
end

#paramsparams_hash (readonly)

The request parameters to be signed

Returns:

  • (params_hash)


47
48
49
# File 'lib/simple_oauth/header.rb', line 47

def params
  @params
end

Class Method Details

.decodeString

Alias for unescape

Parameters:

  • value (String, _ToS)

Returns:

  • (String)


94
# File 'sig/simple_oauth.rbs', line 94

def self.decode: (String | _ToS value) -> String

.encodeString

Alias for escape

Parameters:

  • value (String, _ToS)

Returns:

  • (String)


88
# File 'sig/simple_oauth.rbs', line 88

def self.encode: (String | _ToS value) -> String

.escapeString

Percent-encodes a value according to OAuth specification

Parameters:

  • value (String, _ToS)

Returns:

  • (String)


85
# File 'sig/simple_oauth.rbs', line 85

def self.escape: (String | _ToS value) -> String

.unescapeString

Decodes a percent-encoded value

Parameters:

  • value (String, _ToS)

Returns:

  • (String)


91
# File 'sig/simple_oauth.rbs', line 91

def self.unescape: (String | _ToS value) -> String

Instance Method Details

#attributessigned_attributes_hash

Extracts valid OAuth attributes from options (excludes realm per RFC 5849)

Returns:

  • (signed_attributes_hash)


186
187
188
189
# File 'lib/simple_oauth/header.rb', line 186

def attributes
  validate_option_keys!
  options.slice(*ATTRIBUTE_KEYS).transform_keys { |key| :"#{OAUTH_PREFIX}#{key}" }
end

#build_options(oauth, body) ⇒ oauth_options

Builds OAuth options from input (hash or header string)

Parameters:

  • oauth (oauth_options, String)
  • body (String, nil)

Returns:

  • (oauth_options)


163
164
165
166
167
168
169
# File 'lib/simple_oauth/header.rb', line 163

def build_options(oauth, body)
  if oauth.is_a?(Hash)
    self.class.default_options(body).merge(oauth.transform_keys(&:to_sym))
  else
    self.class.parse(oauth)
  end
end

#header_attributessigned_attributes_hash

Returns OAuth attributes including realm for Authorization header output

Returns:

  • (signed_attributes_hash)


212
213
214
215
216
# File 'lib/simple_oauth/header.rb', line 212

def header_attributes
  attrs = attributes
  attrs[:realm] = options.fetch(:realm) if options[:realm]
  attrs
end

#normalize_uri(url) ⇒ URI::Generic

Normalizes and parses a URL into a URI object

Parameters:

Returns:



150
151
152
153
154
155
# File 'lib/simple_oauth/header.rb', line 150

def normalize_uri(url)
  URI.parse(url.to_s).tap do |uri|
    uri.normalize!
    uri.fragment = nil
  end
end

#normalized_attributesString

Builds the normalized OAuth attributes string for the Authorization header

Returns:

  • (String)


175
176
177
178
179
180
# File 'lib/simple_oauth/header.rb', line 175

def normalized_attributes
  signed_attributes
    .sort_by { |key, _| key }
    .map { |key, value| "#{key}=\"#{Header.escape(value)}\"" }
    .join(", ")
end

#normalized_paramsString

Normalizes and sorts all request parameters for signing

Returns:

  • (String)


258
259
260
261
262
263
264
# File 'lib/simple_oauth/header.rb', line 258

def normalized_params
  signature_params
    .map { |key, value| [Header.escape(key), Header.escape(value)] }
    .sort
    .map { |pair| pair.join("=") }
    .join("&")
end

#secretString

Builds the secret string from consumer and token secrets

Returns:

  • (String)


242
243
244
# File 'lib/simple_oauth/header.rb', line 242

def secret
  options.values_at(:consumer_secret, :token_secret).map { |v| Header.escape(v) }.join("&")
end

#signatureString

Computes the OAuth signature using the configured signature method

Returns:

  • (String)


232
233
234
235
236
# File 'lib/simple_oauth/header.rb', line 232

def signature
  sig_method = options.fetch(:signature_method)
  sig_secret = Signature.rsa?(sig_method) ? options[:consumer_secret] : secret
  Signature.sign(sig_method, sig_secret, signature_base)
end

#signature_baseString

Builds the signature base string from method, URL, and params

Returns:

  • (String)


250
251
252
# File 'lib/simple_oauth/header.rb', line 250

def signature_base
  [method, url, normalized_params].map { |v| Header.escape(v) }.join("&")
end

#signature_paramsArray[untyped]

Collects all parameters to include in signature

Returns:

  • (Array[untyped])


270
271
272
# File 'lib/simple_oauth/header.rb', line 270

def signature_params
  attributes.to_a + params.to_a + url_params
end

#signed_attributessigned_attributes_hash

Returns the OAuth attributes including the signature

Returns:

  • (signed_attributes_hash)


139
140
141
# File 'lib/simple_oauth/header.rb', line 139

def signed_attributes
  header_attributes.merge(oauth_signature: signature)
end

#to_sString

Returns the OAuth Authorization header string

Returns:

  • (String)


111
112
113
# File 'lib/simple_oauth/header.rb', line 111

def to_s
  "#{OAUTH_SCHEME} #{normalized_attributes}"
end

#urlString

Returns the normalized URL without query string or fragment

Returns:

  • (String)


98
99
100
# File 'lib/simple_oauth/header.rb', line 98

def url
  @uri.dup.tap { |uri| uri.query = nil }.to_str
end

#url_paramsArray[untyped]

Extracts query parameters from the request URL

Returns:

  • (Array[untyped])


222
223
224
225
226
# File 'lib/simple_oauth/header.rb', line 222

def url_params
  CGI.parse(@uri.query || "").flat_map do |key, values|
    values.sort.map { |value| [key, value] }
  end
end

#valid?(secrets = {}) ⇒ Boolean

Validates the signature in the header against the provided secrets

Parameters:

  • secrets (oauth_options) (defaults to: {})

Returns:

  • (Boolean)


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

def valid?(secrets = {})
  original_options = options.dup #: Hash[Symbol, untyped]
  options.merge!(secrets)
  options.fetch(:signature).eql?(signature)
ensure
  options.replace(original_options)
end

#validate_option_keys!void

This method returns an undefined value.

Validates that no unknown keys are present in options



196
197
198
199
200
201
202
203
# File 'lib/simple_oauth/header.rb', line 196

def validate_option_keys!
  return if options[:ignore_extra_keys]

  extra_keys = options.keys - ATTRIBUTE_KEYS - IGNORED_KEYS
  return if extra_keys.empty?

  raise InvalidOptionsError, "Unknown option keys: #{extra_keys.map(&:inspect).join(", ")}"
end