simple_oauth 0.5.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "error"
4
+ require_relative "response_body"
5
+
6
+ module SimpleOAuth
7
+ module OAuth2
8
+ # An access token from a successful token response, per RFC 6749 Section 5.1
9
+ #
10
+ # @api public
11
+ # @example Parse a token response
12
+ # token = SimpleOAuth::OAuth2::Token.from_response(status: 200, body: response_body)
13
+ # token.access_token # => "2YotnFZFEjr1zCsicMWpAA"
14
+ class Token
15
+ # The description of a token response that carries no usable access token
16
+ NO_ACCESS_TOKEN = "token response has no access_token"
17
+ # The description of a token response whose lifetime is not a number of seconds
18
+ INVALID_EXPIRES_IN = "token response has an invalid expires_in"
19
+ # The error message for an access token that cannot be used
20
+ INVALID_ACCESS_TOKEN = "The access_token must be a non-empty String"
21
+ # The error message for a token lifetime that is not a number of seconds
22
+ INVALID_LIFETIME = "The expires_in must be a number of seconds"
23
+
24
+ # The access token
25
+ #
26
+ # @api public
27
+ # @return [String] the access token
28
+ # @example
29
+ # token.access_token # => "2YotnFZFEjr1zCsicMWpAA"
30
+ attr_reader :access_token
31
+
32
+ # The token type, such as bearer
33
+ #
34
+ # @api public
35
+ # @return [String, nil] the token type
36
+ # @example
37
+ # token.token_type # => "bearer"
38
+ attr_reader :token_type
39
+
40
+ # The lifetime of the access token in seconds
41
+ #
42
+ # @api public
43
+ # @return [Integer, nil] the lifetime in seconds
44
+ # @example
45
+ # token.expires_in # => 3600
46
+ attr_reader :expires_in
47
+
48
+ # The refresh token, if one was issued
49
+ #
50
+ # @api public
51
+ # @return [String, nil] the refresh token
52
+ # @example
53
+ # token.refresh_token # => "tGzv3JOkF0XG5Qx2TlKWIA"
54
+ attr_reader :refresh_token
55
+
56
+ # The granted scope, as a space-delimited string
57
+ #
58
+ # @api public
59
+ # @return [String, nil] the granted scope
60
+ # @example
61
+ # token.scope # => "tweet.read users.read"
62
+ attr_reader :scope
63
+
64
+ # The time when the access token expires
65
+ #
66
+ # @api public
67
+ # @return [Time, nil] the expiration time
68
+ # @example
69
+ # token.expires_at # => 2026-09-11 13:00:00 UTC
70
+ attr_reader :expires_at
71
+
72
+ # Every parameter of the token response, including nonstandard ones
73
+ #
74
+ # @api public
75
+ # @return [Hash{String => Object}] the parameters
76
+ # @example
77
+ # token.params["example_parameter"] # => "example_value"
78
+ attr_reader :params
79
+
80
+ # Check whether a value is usable as an access token (RFC 6749 Section A.12)
81
+ #
82
+ # @api private
83
+ # @param value [Object] the value from the token response
84
+ # @return [Boolean] true if the value is a non-empty String
85
+ # @example
86
+ # SimpleOAuth::OAuth2::Token.access_token?("2YotnFZFEjr1zCsicMWpAA") # => true
87
+ def self.access_token?(value)
88
+ value.is_a?(String) && !value.empty?
89
+ end
90
+
91
+ # Check whether a value is usable as a token lifetime (RFC 6749 Section 5.1)
92
+ #
93
+ # @api private
94
+ # @param value [Object] the value from the token response
95
+ # @return [Boolean] true if the value is absent, or a number of seconds
96
+ # @example
97
+ # SimpleOAuth::OAuth2::Token.expires_in?(3600) # => true
98
+ def self.expires_in?(value)
99
+ value.nil? || !Integer(value, exception: false).nil?
100
+ end
101
+
102
+ # The reason the parameters of a token response cannot be used, if there is one
103
+ #
104
+ # @api private
105
+ # @param params [Hash] the token response parameters
106
+ # @return [String, nil] the reason, or nil if the response is usable
107
+ # @example
108
+ # SimpleOAuth::OAuth2::Token.rejection_reason({"access_token" => "abc"}) # => nil
109
+ def self.rejection_reason(params)
110
+ return NO_ACCESS_TOKEN unless access_token?(params["access_token"])
111
+
112
+ INVALID_EXPIRES_IN unless expires_in?(params["expires_in"])
113
+ end
114
+
115
+ # Parse a token response, raising the endpoint's error if it failed
116
+ #
117
+ # @api public
118
+ # @param status [Integer, String] the HTTP status of the response
119
+ # @param body [String, nil] the response body
120
+ # @param issued_at [Time] when the token was issued, used to compute its expiration
121
+ # @return [Token] the token
122
+ # @raise [Error] if the response is not successful, or carries no usable token
123
+ # @raise [ArgumentError] if the status is not an HTTP status
124
+ # @example
125
+ # SimpleOAuth::OAuth2::Token.from_response(status: 200, body: '{"access_token":"abc","token_type":"bearer"}')
126
+ def self.from_response(status:, body:, issued_at: Time.now)
127
+ code = Error.http_status(status)
128
+ raise Error.from_response(status:, body:) unless (200..299).cover?(code)
129
+
130
+ params = ResponseBody.parse(body)
131
+ reason = rejection_reason(params)
132
+ raise Error.new(code: nil, description: reason, status: code) if reason
133
+
134
+ new(params, issued_at:)
135
+ end
136
+
137
+ # Initialize a token from the parameters of a token response
138
+ #
139
+ # @api public
140
+ # @param params [Hash] the token response parameters
141
+ # @param issued_at [Time] when the token was issued, used to compute its expiration
142
+ # @raise [KeyError] if the parameters have no access_token
143
+ # @raise [ArgumentError] if the access token cannot be used, or the lifetime is not a number of seconds
144
+ # @example
145
+ # SimpleOAuth::OAuth2::Token.new({"access_token" => "abc", "expires_in" => 3600})
146
+ def initialize(params, issued_at: Time.now)
147
+ @params = params.transform_keys(&:to_s).freeze
148
+ @access_token = validated_access_token
149
+ @token_type = @params["token_type"]
150
+ @expires_in = validated_expires_in
151
+ @refresh_token = @params["refresh_token"]
152
+ @scope = @params["scope"]
153
+ @expires_at = @expires_in&.then { |seconds| issued_at + seconds }
154
+ freeze
155
+ end
156
+
157
+ # The granted scopes
158
+ #
159
+ # @api public
160
+ # @return [Array<String>] the granted scopes
161
+ # @example
162
+ # token.scopes # => ["tweet.read", "users.read"]
163
+ def scopes
164
+ scope.to_s.split
165
+ end
166
+
167
+ # Check whether the access token has expired, or will within a leeway
168
+ #
169
+ # @api public
170
+ # @param leeway [Numeric] seconds before expiration to treat the token as expired
171
+ # @param now [Time] the current time
172
+ # @return [Boolean] true if the token has expired; false if it has not or never expires
173
+ # @example Refresh a token that expires within 30 seconds
174
+ # token.expired?(leeway: 30)
175
+ def expired?(leeway: 0, now: Time.now)
176
+ return false if expires_at.nil?
177
+
178
+ now >= expires_at - leeway
179
+ end
180
+
181
+ private
182
+
183
+ # The access token from the parameters, which must be usable
184
+ #
185
+ # @api private
186
+ # @return [String] the access token
187
+ # @raise [KeyError] if the parameters have no access_token
188
+ # @raise [ArgumentError] if the access token is not a non-empty String
189
+ def validated_access_token
190
+ token = params.fetch("access_token")
191
+ raise ArgumentError, INVALID_ACCESS_TOKEN unless self.class.access_token?(token)
192
+
193
+ token
194
+ end
195
+
196
+ # The lifetime from the parameters, which must be a number of seconds
197
+ #
198
+ # @api private
199
+ # @return [Integer, nil] the lifetime in seconds, or nil if the response carries none
200
+ # @raise [ArgumentError] if the lifetime is not a number of seconds
201
+ def validated_expires_in
202
+ seconds = params["expires_in"]
203
+ raise ArgumentError, INVALID_LIFETIME unless self.class.expires_in?(seconds)
204
+
205
+ seconds && Integer(seconds)
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "oauth2/authorization_response"
4
+ require_relative "oauth2/client"
5
+ require_relative "oauth2/error"
6
+ require_relative "oauth2/pkce"
7
+ require_relative "oauth2/request"
8
+ require_relative "oauth2/response_body"
9
+ require_relative "oauth2/token"
10
+
11
+ module SimpleOAuth
12
+ # OAuth 2.0 request builders and response parsers
13
+ #
14
+ # Like the OAuth 1.0 header builder, these build requests and parse responses without
15
+ # performing HTTP themselves, so they work with any HTTP client.
16
+ #
17
+ # @api public
18
+ # @example Exchange an authorization code for a token
19
+ # client = SimpleOAuth::OAuth2::Client.new(client_id: "id", token_endpoint: "https://example.com/token")
20
+ # pkce = SimpleOAuth::OAuth2::PKCE.generate
21
+ # request = client.authorization_code_request(code: "code", redirect_uri: "https://app.example/cb",
22
+ # code_verifier: pkce.verifier)
23
+ # response = Net::HTTP.post(URI(request.url), request.body, request.headers)
24
+ # token = SimpleOAuth::OAuth2::Token.from_response(status: response.code, body: response.body)
25
+ #
26
+ # @see https://www.rfc-editor.org/rfc/rfc6749 RFC 6749 - The OAuth 2.0 Authorization Framework
27
+ # @see https://www.rfc-editor.org/rfc/rfc7636 RFC 7636 - Proof Key for Code Exchange (PKCE)
28
+ # @see https://www.rfc-editor.org/rfc/rfc7009 RFC 7009 - OAuth 2.0 Token Revocation
29
+ module OAuth2
30
+ end
31
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "strscan"
2
4
  require_relative "errors"
3
5
 
@@ -88,9 +90,13 @@ module SimpleOAuth
88
90
  # @param value [String] the parameter value
89
91
  # @param valid_keys [Array<Symbol>] the valid OAuth parameter keys
90
92
  # @return [void]
93
+ # @raise [SimpleOAuth::ParseError] if the header repeats the parameter
91
94
  def store_if_valid(key, value, valid_keys)
92
95
  parsed_key = valid_keys.find { |k| "oauth_#{k}".eql?(key) }
93
- attributes[parsed_key] = Header.unescape(value) if parsed_key
96
+ return if parsed_key.nil?
97
+ raise ParseError, "Duplicate protocol parameter: #{key}" if attributes.key?(parsed_key)
98
+
99
+ attributes[parsed_key] = Header.unescape(value)
94
100
  end
95
101
 
96
102
  # Verifies that the entire header was parsed
@@ -1,4 +1,5 @@
1
- require "base64"
1
+ # frozen_string_literal: true
2
+
2
3
  require "openssl"
3
4
 
4
5
  module SimpleOAuth
@@ -21,7 +22,7 @@ module SimpleOAuth
21
22
  # SimpleOAuth::Signature.registered?("CUSTOM") # => false
22
23
  module Signature
23
24
  # The hash algorithm of the signature methods RFC 5849 defines
24
- DEFAULT_DIGEST = "SHA1".freeze
25
+ DEFAULT_DIGEST = "SHA1"
25
26
 
26
27
  # Registry of signature method implementations
27
28
  @registry = {}
@@ -66,8 +67,9 @@ module SimpleOAuth
66
67
  # @api public
67
68
  # @return [Array<String>] registered method names
68
69
  # @example
69
- # SimpleOAuth::Signature.methods # => ["hmac_sha1", "hmac_sha256", "rsa_sha1", "plaintext"]
70
- def methods
70
+ # SimpleOAuth::Signature.registered_methods
71
+ # # => ["hmac_sha1", "hmac_sha256", "rsa_sha1", "plaintext"]
72
+ def registered_methods
71
73
  @registry.keys
72
74
  end
73
75
 
@@ -76,11 +78,12 @@ module SimpleOAuth
76
78
  # @api public
77
79
  # @param name [String] the signature method name
78
80
  # @return [Boolean] true if the method uses RSA
81
+ # @raise [ArgumentError] if the signature method is not registered
79
82
  # @example
80
83
  # SimpleOAuth::Signature.rsa?("RSA-SHA1") # => true
81
84
  # SimpleOAuth::Signature.rsa?("HMAC-SHA1") # => false
82
85
  def rsa?(name)
83
- @registry.dig(normalize_name(name), :rsa) || false
86
+ fetch(name).fetch(:rsa)
84
87
  end
85
88
 
86
89
  # Returns the hash algorithm a signature method signs with
@@ -159,7 +162,8 @@ module SimpleOAuth
159
162
  # SimpleOAuth::Signature.decode_base64("AQID")
160
163
  # # => "\x01\x02\x03"
161
164
  def decode_base64(data)
162
- Base64.decode64(data)
165
+ # "m" is Base64, and is lenient about characters outside the alphabet
166
+ data.unpack1("m") #: String
163
167
  end
164
168
 
165
169
  # Encodes binary data as Base64 without newlines
@@ -171,7 +175,8 @@ module SimpleOAuth
171
175
  # SimpleOAuth::Signature.encode_base64("\x01\x02\x03")
172
176
  # # => "AQID"
173
177
  def encode_base64(data)
174
- Base64.strict_encode64(data)
178
+ # "m0" is Base64 with no line breaks
179
+ [data].pack("m0")
175
180
  end
176
181
 
177
182
  private
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # OAuth 1.0 header generation library
2
- module SimpleOauth
4
+ module SimpleOAuth
3
5
  # The current version of the SimpleOAuth gem
4
- VERSION = "0.5.1".freeze
6
+ VERSION = "1.0.0"
5
7
  end
data/lib/simple_oauth.rb CHANGED
@@ -1,10 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "simple_oauth/header"
4
+ require_relative "simple_oauth/oauth2"
2
5
  require_relative "simple_oauth/version"
3
6
 
4
- # OAuth 1.0 header generation and parsing library
7
+ # OAuth 1.0 header and OAuth 2.0 request building library
5
8
  #
6
9
  # SimpleOAuth provides a simple interface for building and verifying
7
- # OAuth 1.0 Authorization headers per RFC 5849.
10
+ # OAuth 1.0 Authorization headers per RFC 5849, and for building
11
+ # OAuth 2.0 requests and parsing their responses (see {SimpleOAuth::OAuth2}).
8
12
  #
9
13
  # @example Building an OAuth header
10
14
  # header = SimpleOAuth::Header.new(
@@ -22,9 +26,4 @@ require_relative "simple_oauth/version"
22
26
  #
23
27
  # @see https://tools.ietf.org/html/rfc5849 RFC 5849 - The OAuth 1.0 Protocol
24
28
  module SimpleOAuth
25
- # Error raised when parsing a malformed OAuth Authorization header
26
- class ParseError < StandardError; end
27
-
28
- # Error raised when invalid options are passed to Header
29
- # (defined in header.rb, exported here for convenience)
30
29
  end
@@ -26,10 +26,10 @@ module SimpleOAuth
26
26
 
27
27
  def parse_form_body: (String | _ToS body) -> Header::oauth_options
28
28
 
29
- private
29
+ # Parses a form-encoded query string or body into parameter pairs
30
+ def form_pairs: (String | _ToS | nil form) -> Array[[String, String]]
30
31
 
31
- # Parses a form-encoded body into the parameter pairs to sign
32
- def form_params: (String? body) -> Array[[String, String]]
32
+ private
33
33
 
34
34
  # Checks whether a request carries a form-encoded body
35
35
  def form_encoded?: (Header::_Request request) -> bool
@@ -41,8 +41,6 @@ module SimpleOAuth
41
41
  # Generates a random nonce for OAuth requests
42
42
  def generate_nonce: () -> String
43
43
 
44
- # Encodes binary data as Base64 without newlines
45
- def encode_base64: (String data) -> String
46
44
  end
47
45
  end
48
46
  end
@@ -0,0 +1,144 @@
1
+ module SimpleOAuth
2
+ # OAuth 2.0 request builders and response parsers
3
+ module OAuth2
4
+ # Parses the JSON bodies returned by OAuth 2.0 endpoints
5
+ module ResponseBody
6
+ def self.parse: (String? body) -> Hash[String, untyped]
7
+ end
8
+
9
+ # The response an authorization server returns to a client's redirect URI
10
+ class AuthorizationResponse
11
+ type response_params = Hash[String | Symbol, String]
12
+
13
+ STATE_MISMATCH: String
14
+ ISSUER_MISMATCH: String
15
+ NO_CODE: String
16
+ DUPLICATE_PARAMETER: String
17
+
18
+ attr_reader code: String
19
+ attr_reader state: String?
20
+ attr_reader issuer: String?
21
+ attr_reader params: Hash[String, String]
22
+
23
+ def self.parse: (String | response_params | nil query, ?state: String?, ?issuer: String?) -> AuthorizationResponse
24
+ def self.parameters: (String | response_params | nil query) -> Hash[String, String]
25
+ def self.reported_error: (Hash[String, String] params) -> Error
26
+ def self.mismatch_reason: (Hash[String, String] params, String? state, String? issuer) -> String?
27
+ def self.matches?: (String? expected, String? actual) -> bool
28
+ def initialize: (response_params params) -> void
29
+ end
30
+
31
+ # Error returned by an OAuth 2.0 endpoint
32
+ class Error < SimpleOAuth::Error
33
+ INVALID_STATUS: String
34
+
35
+ attr_reader code: String?
36
+ attr_reader description: String?
37
+ attr_reader uri: String?
38
+ attr_reader status: Integer?
39
+
40
+ def self.http_status: (Integer | String value) -> Integer
41
+ def self.from_response: (status: Integer | String, body: String?) -> Error
42
+ def initialize: (code: String?, ?description: String?, ?uri: String?, ?status: Integer?) -> void
43
+ end
44
+
45
+ # A Proof Key for Code Exchange verifier and challenge
46
+ class PKCE
47
+ S256: String
48
+ PLAIN: String
49
+ VERIFIER_PATTERN: Regexp
50
+ INVALID_VERIFIER: String
51
+ VERIFIER_BYTES: Integer
52
+
53
+ attr_reader verifier: String
54
+ attr_reader challenge_method: String
55
+ attr_reader challenge: String
56
+
57
+ def self.generate: (?challenge_method: String) -> PKCE
58
+ def initialize: (verifier: String, ?challenge_method: String) -> void
59
+
60
+ private
61
+
62
+ def compute_challenge: () -> String
63
+ def base64_url: (String data) -> String
64
+ end
65
+
66
+ # An HTTP request to an OAuth 2.0 endpoint, built but not sent
67
+ class Request
68
+ attr_reader method: String
69
+ attr_reader url: String
70
+ attr_reader headers: Hash[String, String]
71
+ attr_reader body: String
72
+
73
+ def initialize: (method: String, url: String, headers: Hash[String, String], body: String) -> void
74
+ end
75
+
76
+ # An access token from a successful token response
77
+ class Token
78
+ NO_ACCESS_TOKEN: String
79
+ INVALID_EXPIRES_IN: String
80
+ INVALID_ACCESS_TOKEN: String
81
+ INVALID_LIFETIME: String
82
+
83
+ attr_reader access_token: String
84
+ attr_reader token_type: String?
85
+ attr_reader expires_in: Integer?
86
+ attr_reader refresh_token: String?
87
+ attr_reader scope: String?
88
+ attr_reader expires_at: Time?
89
+ attr_reader params: Hash[String, untyped]
90
+
91
+ def self.access_token?: (untyped value) -> bool
92
+ def self.expires_in?: (untyped value) -> bool
93
+ def self.rejection_reason: (Hash[String, untyped] params) -> String?
94
+ def self.from_response: (status: Integer | String, body: String?, ?issued_at: Time) -> Token
95
+ def initialize: (Hash[String | Symbol, untyped] params, ?issued_at: Time) -> void
96
+ def scopes: () -> Array[String]
97
+ def expired?: (?leeway: Numeric, ?now: Time) -> bool
98
+
99
+ private
100
+
101
+ def validated_access_token: () -> String
102
+ def validated_expires_in: () -> Integer?
103
+ end
104
+
105
+ # An OAuth 2.0 client that builds authorization URLs and endpoint requests
106
+ class Client
107
+ type auth_method = :client_secret_basic | :client_secret_post
108
+ type scope = String | Array[String] | nil
109
+ type form_params = Hash[Symbol, String?]
110
+ type extra_params = Hash[Symbol | String, String?]
111
+
112
+ AUTH_METHODS: Array[Symbol]
113
+ FORM_CONTENT_TYPE: String
114
+ EMPTY_STATE: String
115
+ UNPROTECTED: String
116
+
117
+ attr_reader client_id: String
118
+ attr_reader client_secret: String?
119
+ attr_reader authorization_endpoint: String?
120
+ attr_reader token_endpoint: String?
121
+ attr_reader revocation_endpoint: String?
122
+ attr_reader auth_method: auth_method
123
+
124
+ def initialize: (client_id: String, ?client_secret: String?, ?authorization_endpoint: String?, ?token_endpoint: String?,
125
+ ?revocation_endpoint: String?, ?auth_method: auth_method) -> void
126
+ def public?: () -> bool
127
+ def authorization_url: (redirect_uri: String, pkce: PKCE?, ?state: String?, ?scope: scope, ?params: extra_params) -> String
128
+ def authorization_code_request: (code: String, redirect_uri: String, ?code_verifier: String?, ?params: extra_params) -> Request
129
+ def refresh_token_request: (refresh_token: String, ?scope: scope, ?params: extra_params) -> Request
130
+ def client_credentials_request: (?scope: scope, ?params: extra_params) -> Request
131
+ def revocation_request: (token: String, ?token_type_hint: String?, ?params: extra_params) -> Request
132
+
133
+ private
134
+
135
+ def validate_protection!: (PKCE? pkce, String? state) -> void
136
+ def token_request: (form_params params, extra_params extra) -> Request
137
+ def form_request: (String url, form_params params, extra_params extra) -> Request
138
+ def authenticated: (form_params params) -> [Hash[String, String], form_params]
139
+ def basic_authorization: (String secret) -> String
140
+ def scope_value: (scope scope) -> String?
141
+ def endpoint: (String? url, Symbol name) -> String
142
+ end
143
+ end
144
+ end
@@ -26,7 +26,7 @@ module SimpleOAuth
26
26
  def self.registered?: (String | Symbol name) -> bool
27
27
 
28
28
  # Returns list of registered signature method names
29
- def self.methods: () -> Array[String]
29
+ def self.registered_methods: () -> Array[String]
30
30
 
31
31
  # Checks if a signature method uses RSA
32
32
  def self.rsa?: (String | Symbol name) -> bool
data/sig/simple_oauth.rbs CHANGED
@@ -1,11 +1,15 @@
1
1
  # OAuth 1.0 header generation library
2
2
  module SimpleOAuth
3
+ # The base of every error the library raises
4
+ class Error < StandardError
5
+ end
6
+
3
7
  # Error raised when parsing a malformed OAuth Authorization header
4
- class ParseError < StandardError
8
+ class ParseError < Error
5
9
  end
6
10
 
7
11
  # Error raised when invalid options are passed to Header
8
- class InvalidOptionsError < StandardError
12
+ class InvalidOptionsError < Error
9
13
  end
10
14
 
11
15
  # OAuth percent-encoding utilities
@@ -160,7 +164,7 @@ module SimpleOAuth
160
164
  end
161
165
 
162
166
  # Version module
163
- module SimpleOauth
167
+ module SimpleOAuth
164
168
  # The current version of the SimpleOAuth gem
165
169
  VERSION: String
166
170
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_oauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Richert
@@ -9,36 +9,8 @@ authors:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 1980-01-02 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: base64
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: cgi
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- description: Simply builds and verifies OAuth headers
12
+ dependencies: []
13
+ description: Simply builds and verifies OAuth 1.0 headers and builds OAuth 2.0 requests
42
14
  email:
43
15
  - steve.richert@gmail.com
44
16
  - sferik@gmail.com
@@ -60,6 +32,14 @@ files:
60
32
  - lib/simple_oauth/header.rb
61
33
  - lib/simple_oauth/header/class_methods.rb
62
34
  - lib/simple_oauth/header/params.rb
35
+ - lib/simple_oauth/oauth2.rb
36
+ - lib/simple_oauth/oauth2/authorization_response.rb
37
+ - lib/simple_oauth/oauth2/client.rb
38
+ - lib/simple_oauth/oauth2/error.rb
39
+ - lib/simple_oauth/oauth2/pkce.rb
40
+ - lib/simple_oauth/oauth2/request.rb
41
+ - lib/simple_oauth/oauth2/response_body.rb
42
+ - lib/simple_oauth/oauth2/token.rb
63
43
  - lib/simple_oauth/parser.rb
64
44
  - lib/simple_oauth/signature.rb
65
45
  - lib/simple_oauth/version.rb
@@ -69,6 +49,7 @@ files:
69
49
  - sig/simple_oauth.rbs
70
50
  - sig/simple_oauth/header/class_methods.rbs
71
51
  - sig/simple_oauth/header/params.rbs
52
+ - sig/simple_oauth/oauth2.rbs
72
53
  - sig/simple_oauth/parser.rbs
73
54
  - sig/simple_oauth/signature.rbs
74
55
  - sig/strscan.rbs
@@ -97,5 +78,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
78
  requirements: []
98
79
  rubygems_version: 4.0.20
99
80
  specification_version: 4
100
- summary: Simply builds and verifies OAuth headers
81
+ summary: Simply builds and verifies OAuth 1.0 headers and builds OAuth 2.0 requests
101
82
  test_files: []