devise_token_auth 0.1.20 → 0.1.21.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +274 -77
  3. data/app/controllers/devise_token_auth/auth_controller.rb +4 -1
  4. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +8 -2
  5. data/app/controllers/devise_token_auth/confirmations_controller.rb +1 -1
  6. data/app/controllers/devise_token_auth/passwords_controller.rb +3 -3
  7. data/app/controllers/devise_token_auth/registrations_controller.rb +1 -1
  8. data/app/controllers/devise_token_auth/sessions_controller.rb +1 -1
  9. data/app/models/{user.rb → devise_token_auth/concerns/user.rb} +28 -23
  10. data/config/initializers/devise.rb +4 -64
  11. data/config/routes.rb +2 -14
  12. data/lib/devise_token_auth/engine.rb +5 -1
  13. data/lib/devise_token_auth/rails/routes.rb +36 -0
  14. data/lib/devise_token_auth/version.rb +1 -1
  15. data/lib/generators/devise_token_auth/USAGE +23 -5
  16. data/lib/generators/devise_token_auth/install_generator.rb +69 -5
  17. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +5 -0
  18. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +56 -0
  19. data/lib/generators/devise_token_auth/templates/user.rb +3 -0
  20. data/test/controllers/demo_controller_test.rb +39 -4
  21. data/test/controllers/devise_token_auth/auth_controller_test.rb +98 -0
  22. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +37 -2
  23. data/test/controllers/devise_token_auth/passwords_controller_test.rb +38 -2
  24. data/test/controllers/devise_token_auth/registrations_controller_test.rb +31 -4
  25. data/test/controllers/devise_token_auth/sessions_controller_test.rb +32 -0
  26. data/test/dummy/app/assets/images/omniauth-provider-settings.png +0 -0
  27. data/test/dummy/app/models/mang.rb +3 -0
  28. data/test/dummy/app/models/user.rb +3 -0
  29. data/test/dummy/config/initializers/devise_token_auth.rb +5 -0
  30. data/test/dummy/config/routes.rb +16 -1
  31. data/test/dummy/db/development.sqlite3 +0 -0
  32. data/{lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb → test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb} +0 -0
  33. data/test/dummy/db/migrate/{20140714223034_devise_token_auth_create_users.rb → 20140715061805_devise_token_auth_create_mangs.rb} +7 -7
  34. data/test/dummy/db/schema.rb +35 -4
  35. data/test/dummy/db/test.sqlite3 +0 -0
  36. data/test/dummy/log/development.log +7601 -0
  37. data/test/dummy/log/test.log +128490 -0
  38. data/test/fixtures/mangs.yml +31 -0
  39. data/test/test_helper.rb +13 -9
  40. metadata +22 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6ab41d164c19d7e8f369d95089fb6fc30204720
4
- data.tar.gz: 0d2f92ca77514e7a9f7fd78428b166b2cca55ad9
3
+ metadata.gz: cceda7b13b2df7fdd541d948992dbc48b7dfd3a1
4
+ data.tar.gz: 8fd2c90a8d52644a61a38e4e6509c5c089858661
5
5
  SHA512:
6
- metadata.gz: 2319bd31ab71d0c6a56d6a43c24e5e6cf8b8518f6f86eeaab5cbe968113cd3c654fd44b341a0ccf669800396649b454dc49f53919daf0f8abb2bf6167aab0d57
7
- data.tar.gz: b631992bc2852a8e6faebba8288fce061e65d94c13b09a76f85edeea63c37fefb169d0b40e16dfe791b89e6b35f6dad6b30b1120d20bd64c535b2fb0d25d8034
6
+ metadata.gz: 3ef99d9eb62eecc7cfca98cd68ae981e1411e48ddf9da3a1a1c0315dfea9e53e141cb4a2a0e9dcd23f0ab8f4184243cfde9a24e202d5fde5c1532ea094c3bb4b
7
+ data.tar.gz: 9219e6c4029c2fa29ff17b78078814295327794e322f8228ddcf03ed1795235040a29297100882da3c6b66152ef063c304bae34f597e48d6d7d2f94555cf86af
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Devise Token Auth
2
2
 
3
3
  ![build](https://travis-ci.org/lynndylanhurley/devise_token_auth.svg)
4
+ [![Code Climate](https://codeclimate.com/github/lynndylanhurley/devise_token_auth.png)](https://codeclimate.com/github/lynndylanhurley/devise_token_auth)
5
+ [![Test Coverage](https://codeclimate.com/github/lynndylanhurley/devise_token_auth/coverage.png)](https://codeclimate.com/github/lynndylanhurley/devise_token_auth)
4
6
 
5
7
  This gem provides simple, secure token based authentication.
6
8
 
@@ -31,30 +33,74 @@ Then install the gem using bundle:
31
33
  bundle install
32
34
  ~~~
33
35
 
34
- ## Configuration
35
- You will need to create a user model, and you may want to alter some of the default settings. Run the following to generate the migrations and initializer files:
36
+ # Configuration TLDR;
37
+
38
+ You will need to create a user model, define routes, and you may want to alter some of the default settings for this gem. Run the following to append the routes and generate the model, migration, and initializer files:
36
39
 
37
40
  ~~~bash
38
- rails g devise_token_auth:install
41
+ rails g devise_token_auth:install [USER_CLASS] [MOUNT_PATH]
39
42
  ~~~
40
43
 
41
- This will create a migrations file in the `db/migrate` directory. Inspect the migrations file and add additional columns if necessary, then run the migration:
44
+ This generator accepts the following optional arguments:
42
45
 
43
- ~~~bash
44
- rake db:migrate
45
- ~~~
46
+ | Argument | Default | Description |
47
+ |---|---|---|
48
+ | USER_CLASS | `User` | The name of the class to use for user authentication. |
49
+ | MOUNT_PATH | `auth` | The path at which to mount the authentication routes. [Read more](#usage). |
50
+
51
+ The following events will take place when using the install generator:
52
+
53
+ * An initializer will be created at `config/initializers/devise_token_auth.rb`. [Read more](#initializer-settings).
54
+
55
+ * A model will be created in the `app/models` directory. If the model already exists, a concern will be included at the top of the file. [Read more](#model-concerns).
56
+
57
+ * Routes will be appended to file at `config/routes.rb`. [Read more](#mounting-routes).
58
+
59
+ * A migration file will be created in the `db/migrate` directory. Inspect the migrations file, add additional columns if necessary, and then run the migration:
60
+
61
+ ~~~bash
62
+ rake db:migrate
63
+ ~~~
64
+
65
+ [Jump here](#configuration-cont) for more configuration information.
66
+
67
+ # Usage TLDR;
68
+
69
+ The following routes are available for use by your client. These routes live relative to the path at which this engine is mounted (`/auth` by default). These routes correspond to the defaults used by the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js.
70
+
71
+ | path | method | purpose |
72
+ |:-----|:-------|:--------|
73
+ | / | POST | email registration. accepts **`email`**, **`password`**, and **`password_confirmation`** params. |
74
+ | /sign_in | POST | email authentication. accepts **`email`** and **`password`** as params. |
75
+ | /sign_out | DELETE | invalidate tokens (end session) |
76
+ | /:provider | GET | set this route as the destination for client authentication. ideally this will happen in an external window or popup. [Read more](#omniauth-authentication). |
77
+ | /:provider/callback | GET/POST | destination for the oauth2 provider's callback uri. `postMessage` events containing the authenticated user's data will be sent back to the main client window from this page. [Read more](#omniauth-authentication). |
78
+ | /validate_token | POST | use this route to validate tokens on return visits to the client. accepts **`uid`** and **`auth_token`** as params. these values should correspond to the columns in your `User` table of the same names. |
79
+ | /password | POST | send password email to users that registered by email. accepts **`email`** and **`redirect_url`** as params. The user matching the `email` param will be sent instructions on how to reset their password. `redirect_url` is the url to which the user will be redirected after visiting the link contained in the email. |
80
+ | /password | PUT | password change for users that registered by email. accepts **`password`** and **`password_confirmation`** as params. |
81
+ | /password/edit | GET | verify user by password reset token. must contain **`reset_password_token`** and **`redirect_url`** as params. These values will be set automatically by the confirmation email that is generated by the password reset request. |
82
+
83
+ [Jump here](#usage-cont) for more usage information.
46
84
 
47
- An initializer will also be created at `config/initializers/devise_token_auth.rb`. The following settings are available for configuration:
85
+ # Configuration cont.
86
+
87
+ ## Initializer settings
88
+
89
+ The following settings are available for configuration in `config/initializers/devise_token_auth.rb`:
90
+
91
+ | Name | Default | Description|
92
+ |---|---|---|
93
+ | **`change_headers_on_each_request`** | `true` | By default the authorization headers will change after each request. The client is responsible for keeping track of the changing tokens. The [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js does this out of the box. While this implementation is more secure, it can be difficult to manage. Set this to false to prevent the `Authorization` header from changing after each request. [Read more](#about-token-management). |
94
+ | **`token_lifespan`** | `2.weeks` | Set the length of your tokens' lifespans. Users will need to re-authenticate after this duration of time has passed since their last login. |
95
+ | **`batch_request_buffer_throttle`** | `5.seconds` | Sometimes it's necessary to make several requests to the API at the same time. In this case, each request in the batch will need to share the same auth token. This setting determines how far apart the requests can be while still using the same auth token. [Read more](#about-batch-requests). |
96
+ | **`omniauth_prefix`** | `"/omniauth"` | This route will be the prefix for all oauth2 redirect callbacks. For example, using the default '/omniauth' setting, the github oauth2 provider will redirect successful authentications to '/omniauth/github/callback'. [Read more](#omniauth-provider-settings). |
48
97
 
49
- * **`change_headers_on_each_request`** _Default: true_. By default the authorization headers will change after each request. The client is responsible for keeping track of the changing tokens. The [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js does this out of the box. While this implementation is more secure, it can be difficult to manage. Set this to false to prevent the `Authorization` header from changing after each request.
50
- * **`token_lifespan`** _Default: 2.weeks_. Set the length of your tokens' lifespans. Users will need to re-authenticate after this duration of time has passed since their last login.
51
- * **`batch_request_buffer_throttle`** _Default: 2.seconds_. Sometimes it's necessary to make several requests to the API at the same time. In this case, each request in the batch will need to share the same auth token. This setting determines how far apart the requests can be while still using the same auth token.
52
98
 
53
99
  ## Omniauth authentication
54
100
 
55
- If you wish to use omniauth authentication, add all of your desired authentication provider gems as well.
101
+ If you wish to use omniauth authentication, add all of your desired authentication provider gems to your `Gemfile`.
56
102
 
57
- ##### Omniauth example using github, facebook, and google:
103
+ **Omniauth example using github, facebook, and google**:
58
104
  ~~~ruby
59
105
  gem 'omniauth-github', :git => 'git://github.com/intridea/omniauth-github.git'
60
106
  gem 'omniauth-facebook', :git => 'git://github.com/mkdynamic/omniauth-facebook.git'
@@ -65,12 +111,13 @@ Then run `bundle install`.
65
111
 
66
112
  [List of oauth2 providers](https://github.com/intridea/omniauth/wiki/List-of-Strategies)
67
113
 
68
- #### Provider settings
114
+ ## Omniauth provider settings
115
+
69
116
  In `config/initializers/omniauth.rb`, add the settings for each of your providers.
70
117
 
71
118
  These settings must be obtained from the providers themselves.
72
119
 
73
- ##### Example using github, facebook, and google:
120
+ **Example using github, facebook, and google**:
74
121
  ~~~ruby
75
122
  # config/initializers/omniauth.rb
76
123
  Rails.application.config.middleware.use OmniAuth::Builder do
@@ -82,8 +129,44 @@ end
82
129
 
83
130
  The above example assumes that your provider keys and secrets are stored in environmental variables. Use the [figaro](https://github.com/laserlemon/figaro) gem (or [dotenv](https://github.com/bkeepers/dotenv) or [secrets.yml](https://github.com/rails/rails/blob/v4.1.0/railties/lib/rails/generators/rails/app/templates/config/secrets.yml) or equivalent) to accomplish this.
84
131
 
132
+ #### Omniauth callback settings
133
+
134
+ The "Callback URL" setting that you set with your provider must correspond to the [omniauth prefix](#initializer-settings) setting defined by this app. **This will be different than the omniauth route that is used by your client application**.
135
+
136
+ For example, the demo app uses the default `omniauth_prefix` setting `/omniauth`, so the "Authorization callback URL" for github must be set to "http://devise-token-auth-demo.herokuapp.com**/omniauth**/github/callback".
137
+
138
+ **Github example for the demo site**:
139
+ ![password reset flow](https://github.com/lynndylanhurley/devise_token_auth/raw/master/test/dummy/app/assets/images/omniauth-provider-settings.png)
140
+
141
+ The url for github authentication will be different for the client. The client should visit the API at `/[MOUNT_PATH]/:provider` for omniauth authentication.
142
+
143
+ For example, given that the app is mounted using the following settings:
144
+
145
+ ~~~ruby
146
+ # config/routes.rb
147
+ mount_devise_token_auth_for 'User', at: '/auth'
148
+ ~~~
149
+
150
+ The client configuration for github should look like this:
151
+
152
+ **Angular.js setting for authenticating using github**:
153
+ ~~~javascript
154
+ angular.module('myApp', ['ng-token-auth'])
155
+ .config(function($authProvider) {
156
+ $authProvider.configure({
157
+ apiUrl: 'http://api.example.com'
158
+ authProviderPaths: {
159
+ github: '/auth/github' // <-- note that this is different than what was set with github
160
+ }
161
+ });
162
+ });
163
+ ~~~
164
+
165
+ This incongruence is necessary to support multiple user classes and mounting points.
85
166
 
86
- **Note for [pow](http://pow.cx/) and [xip.io](http://xip.io) users**: if you receive `redirect-uri-mismatch` errors from your provider when using pow or xip.io urls, set the following in your development config:
167
+ #### Note for [pow](http://pow.cx/) and [xip.io](http://xip.io) users
168
+
169
+ If you receive `redirect-uri-mismatch` errors from your provider when using pow or xip.io urls, set the following in your development config:
87
170
 
88
171
  ~~~ruby
89
172
  # config/environments/development.rb
@@ -95,8 +178,6 @@ OmniAuth.config.full_host = "http://app-name.dev"
95
178
  OmniAuth.config.full_host = "http://xxx.xxx.xxx.app-name.xip.io"
96
179
  ~~~
97
180
 
98
- There may be a better way to accomplish this. Please post an issue if you have any suggestions.
99
-
100
181
  ## Email authentication
101
182
  If you wish to use email authentication, you must configure your Rails application to send email. [Read here](http://guides.rubyonrails.org/action_mailer_basics.html) for more information.
102
183
 
@@ -112,19 +193,6 @@ Rails.application.configure do
112
193
  end
113
194
  ~~~
114
195
 
115
- ## Routes
116
-
117
- The authentication routes must be mounted to your project.
118
-
119
- In `config/routes.rb`, add the following line:
120
-
121
- ~~~ruby
122
- # config/routes.rb
123
- mount DeviseTokenAuth::Engine => "/auth"
124
- ~~~
125
-
126
- Note that you can mount this engine to any route that you like. `/auth` is used to conform to the defaults of the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module.
127
-
128
196
  ## CORS
129
197
 
130
198
  If your API and client live on different domains, you will need to configure your Rails API to allow cross origin requests. The [rack-cors](https://github.com/cyu/rack-cors) gem can be used to accomplish this.
@@ -156,57 +224,33 @@ Make extra sure that the `Access-Control-Expose-Headers` includes `Authorization
156
224
 
157
225
  CORS may not be possible with older browsers (IE8, IE9). I usually set up a proxy for those browsers. See the [ng-token-auth readme](https://github.com/lynndylanhurley/ng-token-auth) for more information.
158
226
 
159
- # Usage
160
-
161
- The following routes are available for use by your client. These routes live relative to the path at which this engine is mounted (`/auth` in the example above).
162
-
163
- | path | method | purpose |
164
- |:-----|:-------|:--------|
165
- | / | POST | email registration. accepts **`email`**, **`password`**, and **`password_confirmation`** params. |
166
- | /sign_in | POST | email authentication. accepts **`email`** and **`password`** as params. |
167
- | /sign_out | DELETE | invalidate tokens (end session) |
168
- | /:provider | GET | set this route as the destination for client authentication. ideally this will happen in an external window or popup. |
169
- | /:provider/callback | GET/POST | destination for the oauth2 provider's callback uri. `postMessage` events containing the authenticated user's data will be sent back to the main client window from this page. |
170
- | /validate_token | POST | use this route to validate tokens on return visits to the client. accepts **`uid`** and **`auth_token`** as params. these values should correspond to the columns in your `User` table of the same names. |
171
- | /password | POST | send password email to users that registered by email. accepts **`email`** and **`redirect_url`** as params. The user matching the `email` param will be sent instructions on how to reset their password. `redirect_url` is the url to which the user will be redirected after visiting the link contained in the email. |
172
- | /password | PUT | password change for users that registered by email. accepts **`password`** and **`password_confirmation`** as params. |
173
- | /password/edit | GET | verify user by password reset token. must contain **`reset_password_token`** and **`redirect_url`** as params. These values will be set automatically by the confirmation email that is generated by the password reset request. |
227
+ # Usage cont.
174
228
 
175
- If you're using [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) for angular.js, then your client is ready to go.
229
+ ## Mounting Routes
176
230
 
231
+ The authentication routes must be mounted to your project. This gem includes a route helper for this purpose:
177
232
 
178
- ## Identifying users in controllers
233
+ **`mount_devise_token_auth_for`** - similar to `devise_for`, this method is used to append the routes necessary for user authentication. This method accepts the following arguments:
179
234
 
180
- The authentication information should be included by the client in the `Authorization` header of each request. The header should follow this format:
235
+ | Argument | Type | Description |
236
+ |---|---|---|
237
+ |`class_name`| string | The name of the class to use for authentication. This class must include the [model concern described here](#model-concerns). |
238
+ | `options` | object | The [routes to be used for authentication](#usage) will be prefixed by the path specified in the `at` param of this object. |
181
239
 
182
- ##### Authorization header example:
183
- ~~~
184
- token=wwwww client=xxxxx expiry=yyyyy uid=zzzzz
240
+ **Example**:
241
+ ~~~ruby
242
+ # config/routes.rb
243
+ mount_devise_token_auth_for 'User', at: '/auth'
185
244
  ~~~
186
245
 
187
- The `Authorization` header is made up of the following components:
188
-
189
- * **`token`**: This serves as the user's password for each request. A hashed version of this value is stored in the database for later comparison. This value should be changed on each request.
190
- * **`client`**: This enables the use of multiple simultaneous sessions on different clients. (For example, a user may want to be authenticated on both their phone and their laptop at the same time.)
191
- * **`expiry`**: The date at which the current session will expire. This can be used by clients to invalidate expired tokens without the need for an API request.
192
- * **`uid`**: A unique value that is used to identify the user. This is necessary because searching the DB for users by their access token will open the API up to timing attacks.
193
-
194
- The `Authorization` header required for each request will be available in the response from the previous request. If you are using the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js, this functionality is already provided.
195
-
196
- ## Handling batch requests
246
+ You can mount this engine to any route that you like. `/auth` is used by default to conform with the defaults of the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module.
197
247
 
198
- Sometimes it's necessary to send several concurrent requests to the API. In these cases, the concurrent requests will need to share the same auth token (tokens are usually changed after each request). [Read here](https://github.com/lynndylanhurley/ng-token-auth#about-batch-requests) for an overview on how this gem deals with batch requests.
199
248
 
200
- ## The `User` model
249
+ ## Controller Concerns
201
250
 
202
- The user model will contain the following public methods (read the above section for context on `token` and `client`):
203
- * **`valid_token?`**: check if an authentication token is valid. Accepts `token` and `client` as arguments. Returns a boolean.
204
- * **`create_new_auth_token`**: creates a new auth token with all of the necessary metadata. Accepts `client` as an optional argument. Will generate a new `client` if none is provided. Returns the `Authorization` header that should be sent by the client as a string.
205
- * **`build_auth_header`**: generates the auth header that should be sent to the client with the next request. Accepts `token` and `client` as arguments. Returns a string.
251
+ ##### DeviseTokenAuth::Concerns::SetUserByToken
206
252
 
207
- ## DeviseTokenAuth::Concerns::SetUserByToken
208
-
209
- This gem includes a [Rails concern](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html) that can be used to identify users by the `Authorization` header.
253
+ This gem includes a [Rails concern](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html) called `DeviseTokenAuth::Concerns::SetUserByToken`. This concern can be used can be used in controllers to identify users by their `Authorization` header.
210
254
 
211
255
  This concern runs a [before_action](http://guides.rubyonrails.org/action_controller_overview.html#filters), setting the `@user` variable for use in your controllers. The user will be signed in via devise for the duration of the request.
212
256
 
@@ -239,12 +283,170 @@ class TestController < ApplicationController
239
283
  end
240
284
  ~~~
241
285
 
286
+ The authentication information should be included by the client in the `Authorization` header of each request. The header should follow this format:
287
+
288
+ ##### Authorization header example:
289
+ ~~~
290
+ token=wwwww client=xxxxx expiry=yyyyy uid=zzzzz
291
+ ~~~
292
+
293
+ The `Authorization` header is made up of the following components:
294
+
295
+ * **`token`**: This serves as the user's password for each request. A hashed version of this value is stored in the database for later comparison. This value should be changed on each request.
296
+ * **`client`**: This enables the use of multiple simultaneous sessions on different clients. (For example, a user may want to be authenticated on both their phone and their laptop at the same time.)
297
+ * **`expiry`**: The date at which the current session will expire. This can be used by clients to invalidate expired tokens without the need for an API request.
298
+ * **`uid`**: A unique value that is used to identify the user. This is necessary because searching the DB for users by their access token will open the API up to timing attacks.
299
+
300
+ The `Authorization` header required for each request will be available in the response from the previous request. If you are using the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js, this functionality is already provided.
301
+
302
+ ## Model Concerns
303
+
304
+ ##### DeviseTokenAuth::Concerns::SetUserByToken
305
+
306
+ Typical use of this gem will not require the use of any of the following model methods. All authentication should be handled invisibly by the [controller concerns](#controller-concerns) described above.
307
+
308
+ Models that include the `DeviseTokenAuth::Concerns::SetUserByToken` concern will have access to the following public methods (read the above section for context on `token` and `client`):
309
+
310
+ * **`valid_token?`**: check if an authentication token is valid. Accepts a `token` and `client` as arguments. Returns a boolean.
311
+
312
+ **Example**:
313
+ ~~~ruby
314
+ # extract token + client_id from auth header
315
+ client_id = request.headers['Authorization'][/client=(.*?) /,1]
316
+ token = request.headers['Authorization'][/token=(.*?) /,1]
317
+
318
+ @user.valid_token?(token, client_id)
319
+ ~~~
320
+
321
+ * **`create_new_auth_token`**: creates a new auth token with all of the necessary metadata. Accepts `client` as an optional argument. Will generate a new `client` if none is provided. Returns the `Authorization` header that should be sent by the client as a string.
322
+
323
+ **Example**:
324
+ ~~~ruby
325
+ # extract client_id from auth header
326
+ client_id = request.headers['Authorization'][/client=(.*?) /,1]
327
+
328
+ # update token, generate updated auth headers for response
329
+ new_auth_header = @user.create_new_auth_token(client_id)
330
+
331
+ # update response with the header that will be required by the next request
332
+ response.headers["Authorization"] = new_auth_header
333
+ ~~~
334
+
335
+ * **`build_auth_header`**: generates the auth header that should be sent to the client with the next request. Accepts `token` and `client` as arguments. Returns a string.
336
+
337
+ **Example**:
338
+ ~~~ruby
339
+ # create client id and token
340
+ client_id = SecureRandom.urlsafe_base64(nil, false)
341
+ token = SecureRandom.urlsafe_base64(nil, false)
342
+
343
+ # store client + token in user's token hash
344
+ @user.tokens[client_id] = {
345
+ token: BCrypt::Password.create(token),
346
+ expiry: (Time.now + DeviseTokenAuth.token_lifespan).to_i
347
+ }
348
+
349
+ # update token, generate updated auth headers for response
350
+ new_auth_header = @user.create_new_auth_token(token, client_id)
351
+
352
+ # update response with the header that will be required by the next request
353
+ response.headers["Authorization"] = new_auth_header
354
+ ~~~
355
+
356
+ ## Using multiple models
357
+
358
+ This gem supports the use of multiple user models. One possible use case is to authorize visitors using a model called `User`, and to authorize administrators with a model called `Admin` from the same app. Take the following steps to add another authentication model to your app:
359
+
360
+ 1. Run the install generator for the new model.
361
+ ~~~
362
+ rails g devise_token_auth:install Admin admin_auth
363
+ ~~~
364
+
365
+ This will create the `Admin` model and define the model's authentication routes with the base path `/admin_auth`.
366
+
367
+ 1. Define the routes to be used by the `Admin` user within a [`devise_scope`](https://github.com/plataformatec/devise#configuring-routes).
368
+
369
+ **Example**:
370
+ ~~~ruby
371
+ Rails.application.routes.draw do
372
+ # when using multiple models, controllers will default to the first available
373
+ # devise mapping. routes for subsequent devise mappings will need to defined
374
+ # within a `devise_scope` block
375
+
376
+ # define :users as the first devise mapping:
377
+ mount_devise_token_auth_for 'User', at: '/auth'
378
+
379
+ # define :admins as the second devise mapping. routes using this class will
380
+ # need to be defined within a devise_scope as shown below
381
+ mount_devise_token_auth_for "Admin", at: '/admin_auth'
382
+
383
+ # this route will authorize visitors using the User class
384
+ get 'demo/members_only', to: 'demo#members_only'
385
+
386
+ # routes within this block will authorize visitors using the Admin class
387
+ devise_scope :admin do
388
+ get 'demo/admins_only', to: 'demo#admins_only'
389
+ end
390
+ end
391
+ ~~~
392
+
393
+ # Conceptual
394
+
395
+ None of the following information is required to use this gem, but read on if you're curious.
396
+
397
+ ## About token management
398
+
399
+ Tokens should be invalidated after each request to the API. The following diagram illustrates this concept:
400
+
401
+ ![password reset flow](https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/token-update-detail.jpg)
402
+
403
+ During each request, a new token is generated. The `Authorization` header that should be used in the next request is returned in the `Authorization` header of the response to the previous request. The last request in the diagram fails because it tries to use a token that was invalidated by the previous request.
404
+
405
+ The only case where an expired token is allowed is during [batch requests](#about-batch-requests).
406
+
407
+ These measures are taken by default when using this gem.
408
+
409
+ ## About batch requests
410
+
411
+ By default, the API should update the auth token for each request ([read more](#about-token-management)). But sometimes it's neccessary to make several concurrent requests to the API, for example:
412
+
413
+ #####Batch request example
414
+ ~~~javascript
415
+ $scope.getResourceData = function() {
416
+
417
+ $http.get('/api/restricted_resource_1').success(function(resp) {
418
+ // handle response
419
+ $scope.resource1 = resp.data;
420
+ });
421
+
422
+ $http.get('/api/restricted_resource_2').success(function(resp) {
423
+ // handle response
424
+ $scope.resource2 = resp.data;
425
+ });
426
+ };
427
+ ~~~
428
+
429
+ In this case, it's impossible to update the `Authorization` header for the second request with the `Authorization` header of the first response because the second request will begin before the first one is complete. The server must allow these batches of concurrent requests to share the same auth token. This diagram illustrates how batch requests are identified by the server:
430
+
431
+ ![batch request overview](https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/batch-request-overview.jpg)
432
+
433
+ The "5 second" buffer in the diagram is the default used this gem.
434
+
435
+ The following diagram details the relationship between the client, server, and access tokens used over time when dealing with batch requests:
436
+
437
+ ![batch request detail](https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/batch-request-detail.jpg)
438
+
439
+ Note that when the server identifies that a request is part of a batch request, the user's auth token is not updated. The auth token will be updated for the first request in the batch, and then that same token will be returned in the responses for each subsequent request in the batch (as shown in the diagram).
440
+
441
+ This gem automatically manages batch requests. You can change the time buffer for what is considered a batch request using the `batch_request_buffer_throttle` parameter in `config/initializers/devise_token_auth.rb`.
442
+
443
+
242
444
  # Security
243
445
 
244
446
  This gem takes the following steps to ensure security.
245
447
 
246
448
  This gem uses auth tokens that are:
247
- * changed after every request,
449
+ * [changed after every request](#about-token-management),
248
450
  * [of cryptographic strength](http://ruby-doc.org/stdlib-2.1.0/libdoc/securerandom/rdoc/SecureRandom.html),
249
451
  * hashed using [BCrypt](https://github.com/codahale/bcrypt-ruby) (not stored in plain-text),
250
452
  * securely compared (to protect against timing attacks),
@@ -256,11 +458,6 @@ This gem further mitigates timing attacks by using [this technique](https://gist
256
458
 
257
459
  But the most important step is to use HTTPS. You are on the hook for that.
258
460
 
259
- # TODO
260
-
261
- * Write tests
262
- * `User` model is currently baked into this gem. Allow for dynamic definition using concerns (or other means).
263
- * Find a way to expose devise + omniauth configs, maybe using generators.
264
461
 
265
462
  # Contributing
266
463
  Just send a pull request. I will grant you commit access if you send quality pull requests.