@@ -26,14 +26,14 @@ content-MD5 are not present, then a blank string is used in their place. If the
2626timestamp isn't present, a valid HTTP date is automatically added to the
2727request. The canonical string is computed as follows:
2828
29- canonical_string = ' http method, content-type, content-MD5, request URI, timestamp'
29+ ` canonical_string = "#{ http method},#{ content-type},#{ content-MD5},#{ request URI},#{ timestamp}" `
3030
31312 . This string is then used to create the signature which is a Base64 encoded
3232SHA1 HMAC, using the client's private secret key.
3333
34343 . This signature is then added as the ` Authorization ` HTTP header in the form:
3535
36- Authorization = APIAuth ' client access id':' signature from step 2'
36+ ` Authorization = APIAuth "#{ client access id}:#{ signature from step 2}" `
3737
38385 . On the server side, the SHA1 HMAC is computed in the same way using the
3939request headers and the client's secret key, which is known to only
@@ -63,7 +63,9 @@ For older version of Ruby or Rails, please use ApiAuth v2.1 and older.
6363The gem doesn't have any dependencies outside of having a working OpenSSL
6464configuration for your Ruby VM. To install:
6565
66- [sudo] gem install api-auth
66+ ``` bash
67+ [sudo] gem install api-auth
68+ ```
6769
6870Please note the dash in the name versus the underscore.
6971
@@ -89,25 +91,29 @@ Here's a sample implementation of signing a request created with RestClient.
8991Assuming you have a client access id and secret as follows:
9092
9193``` ruby
92- @access_id = " 1044"
93- @secret_key = ApiAuth .generate_secret_key
94+ @access_id = " 1044"
95+ @secret_key = ApiAuth .generate_secret_key
9496```
9597
9698A typical RestClient PUT request may look like:
9799
98100``` ruby
99- headers = { ' Content-MD5' => " e59ff97941044f85df5297e1c302d260" ,
100- ' Content-Type' => " text/plain" ,
101- ' Date' => " Mon, 23 Jan 1984 03:29:56 GMT" }
102- @request = RestClient ::Request .new (:url => " /resource.xml?foo=bar&bar=foo" ,
103- :headers => headers,
104- :method => :put )
101+ headers = { ' Content-MD5' => " e59ff97941044f85df5297e1c302d260" ,
102+ ' Content-Type' => " text/plain" ,
103+ ' Date' => " Mon, 23 Jan 1984 03:29:56 GMT"
104+ }
105+
106+ @request = RestClient ::Request .new (
107+ url: " /resource.xml?foo=bar&bar=foo" ,
108+ headers: headers,
109+ method: :put
110+ )
105111```
106112
107113To sign that request, simply call the ` sign! ` method as follows:
108114
109115``` ruby
110- @signed_request = ApiAuth .sign!(@request , @access_id , @secret_key )
116+ @signed_request = ApiAuth .sign!(@request , @access_id , @secret_key )
111117```
112118
113119The proper ` Authorization ` request header has now been added to that request
@@ -121,33 +127,37 @@ method detection (like Curb or httpi), you can pass the http method as an option
121127into the sign! method like so:
122128
123129``` ruby
124- @signed_request = ApiAuth .sign!(@request , @access_id , @secret_key , :override_http_method => " PUT" )
130+ @signed_request = ApiAuth .sign!(@request , @access_id , @secret_key , :override_http_method => " PUT" )
125131```
126132
127133If you want to use another digest existing in ` OpenSSL::Digest ` ,
128134you can pass the http method as an option into the sign! method like so:
129135
130136``` ruby
131- @signed_request = ApiAuth .sign!(@request , @access_id , @secret_key , :digest => ' sha256' )
137+ @signed_request = ApiAuth .sign!(@request , @access_id , @secret_key , :digest => ' sha256' )
132138```
133139
134140With the ` digest ` option, the ` Authorization ` header will be change from:
135141
136- Authorization = APIAuth 'client access id':'signature'
142+ ```
143+ Authorization = APIAuth 'client access id':'signature'
144+ ```
137145
138146to:
139147
140- Authorization = APIAuth-HMAC-DIGEST_NAME 'client access id':'signature'
148+ ```
149+ Authorization = APIAuth-HMAC-DIGEST_NAME 'client access id':'signature'
150+ ```
141151
142152### ActiveResource Clients
143153
144154ApiAuth can transparently protect your ActiveResource communications with a
145155single configuration line:
146156
147157``` ruby
148- class MyResource < ActiveResource ::Base
149- with_api_auth(access_id, secret_key)
150- end
158+ class MyResource < ActiveResource ::Base
159+ with_api_auth(access_id, secret_key)
160+ end
151161```
152162
153163This will automatically sign all outgoing ActiveResource requests from your app.
@@ -169,26 +179,28 @@ clients as well as verifying incoming API requests.
169179To generate a Base64 encoded API key for a client:
170180
171181``` ruby
172- ApiAuth .generate_secret_key
182+ ApiAuth .generate_secret_key
173183```
174184
175185To validate whether or not a request is authentic:
176186
177187``` ruby
178- ApiAuth .authentic?(signed_request, secret_key)
188+ ApiAuth .authentic?(signed_request, secret_key)
179189```
180190
181191The ` authentic? ` method uses the digest specified in the ` Authorization ` header.
182192For example SHA256 for:
183193
184- Authorization = APIAuth-HMAC-SHA256 'client access id':'signature'
194+ ```
195+ Authorization = APIAuth-HMAC-SHA256 'client access id':'signature'
196+ ```
185197
186198And by default SHA1 if the HMAC-DIGEST is not specified.
187199
188200If you want to force the usage of another digest method, you should pass it as an option parameter:
189201
190202``` ruby
191- ApiAuth .authentic?(signed_request, secret_key, :digest => ' sha256' )
203+ ApiAuth .authentic?(signed_request, secret_key, :digest => ' sha256' )
192204```
193205
194206For security, requests dated older or newer than a certain timespan are considered inauthentic.
@@ -199,13 +211,13 @@ can't be dated into the far future.
199211The default span is 15 minutes, but you can override this:
200212
201213``` ruby
202- ApiAuth .authentic?(signed_request, secret_key, :clock_skew => 60 ) # or 1.minute in ActiveSupport
214+ ApiAuth .authentic?(signed_request, secret_key, :clock_skew => 60 ) # or 1.minute in ActiveSupport
203215```
204216
205217If you want to sign custom headers, you can pass them as an array of strings in the options like so:
206218
207219``` ruby
208- ApiAuth .authentic?(signed_request, secret_key, headers_to_sign: %w[HTTP_HEADER_NAME] )
220+ ApiAuth .authentic?(signed_request, secret_key, headers_to_sign: %w[HTTP_HEADER_NAME] )
209221```
210222
211223With the specified headers values being at the end of the canonical string in the same order.
@@ -216,7 +228,7 @@ In order to obtain the secret key for the client, you first need to look up the
216228client's access_id. ApiAuth can pull that from the request headers for you:
217229
218230``` ruby
219- ApiAuth .access_id(signed_request)
231+ ApiAuth .access_id(signed_request)
220232```
221233
222234Once you've looked up the client's record via the access id, you can then verify
@@ -228,12 +240,12 @@ Here's a sample method that can be used in a `before_action` if your server is a
228240Rails app:
229241
230242``` ruby
231- before_action :api_authenticate
243+ before_action :api_authenticate
232244
233- def api_authenticate
234- @current_account = Account .find_by_access_id(ApiAuth .access_id(request))
235- head(:unauthorized ) unless @current_account && ApiAuth .authentic?(request, @current_account .secret_key)
236- end
245+ def api_authenticate
246+ @current_account = Account .find_by_access_id(ApiAuth .access_id(request))
247+ head(:unauthorized ) unless @current_account && ApiAuth .authentic?(request, @current_account .secret_key)
248+ end
237249```
238250
239251## Development
@@ -246,11 +258,15 @@ To run the tests:
246258
247259Install the dependencies for a particular Rails version by specifying a gemfile in ` gemfiles ` directory:
248260
249- BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle install
261+ ```
262+ BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle install
263+ ```
250264
251265Run the tests with those dependencies:
252266
253- BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle exec rake
267+ ```
268+ BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle exec rake
269+ ```
254270
255271If you'd like to add support for additional HTTP clients, check out the already
256272implemented drivers in ` lib/api_auth/request_drivers ` for reference. All of
0 commit comments