api_guard_grape 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +690 -0
  4. data/Rakefile +21 -0
  5. data/app/controllers/api_guard/application_controller.rb +11 -0
  6. data/app/controllers/api_guard/authentication_controller.rb +31 -0
  7. data/app/controllers/api_guard/passwords_controller.rb +29 -0
  8. data/app/controllers/api_guard/registration_controller.rb +30 -0
  9. data/app/controllers/api_guard/tokens_controller.rb +32 -0
  10. data/config/locales/en.yml +22 -0
  11. data/config/routes.rb +6 -0
  12. data/lib/api_guard.rb +40 -0
  13. data/lib/api_guard/app_secret_key.rb +22 -0
  14. data/lib/api_guard/engine.rb +17 -0
  15. data/lib/api_guard/jwt_auth/authentication.rb +98 -0
  16. data/lib/api_guard/jwt_auth/blacklist_token.rb +35 -0
  17. data/lib/api_guard/jwt_auth/json_web_token.rb +72 -0
  18. data/lib/api_guard/jwt_auth/refresh_jwt_token.rb +46 -0
  19. data/lib/api_guard/models/concerns.rb +27 -0
  20. data/lib/api_guard/modules.rb +26 -0
  21. data/lib/api_guard/resource_mapper.rb +43 -0
  22. data/lib/api_guard/response_formatters/renderer.rb +22 -0
  23. data/lib/api_guard/route_mapper.rb +85 -0
  24. data/lib/api_guard/test/controller_helper.rb +13 -0
  25. data/lib/api_guard/version.rb +5 -0
  26. data/lib/generators/api_guard/controllers/USAGE +11 -0
  27. data/lib/generators/api_guard/controllers/controllers_generator.rb +25 -0
  28. data/lib/generators/api_guard/controllers/templates/authentication_controller.rb +27 -0
  29. data/lib/generators/api_guard/controllers/templates/passwords_controller.rb +25 -0
  30. data/lib/generators/api_guard/controllers/templates/registration_controller.rb +26 -0
  31. data/lib/generators/api_guard/controllers/templates/tokens_controller.rb +28 -0
  32. data/lib/generators/api_guard/initializer/USAGE +8 -0
  33. data/lib/generators/api_guard/initializer/initializer_generator.rb +13 -0
  34. data/lib/generators/api_guard/initializer/templates/initializer.rb +19 -0
  35. metadata +202 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8fa6b87a02bcff0944fd185a949d84c63776d678928ca896fd66ea8b1ad4992a
4
+ data.tar.gz: 29f4c5f87ca08a83ed96ec88f1b186ff9e76e0759b6748e1a603534e2ab16bd4
5
+ SHA512:
6
+ metadata.gz: 9981e401bbd55f0514320a1bf94aeba015f98c38c2b5a2d14cc10a745a487a52ccb134a4ce9043817fdc84c4974340a6bea9e682740c1ece82172ac9654cfae5
7
+ data.tar.gz: 03efd2036116ee5e4fd46b08e7ee08635a702b08e2d5ff9d2d7c36745ede88a89df8197b0db5a39a36b99a63a831d08c283b59e45cca68acc114587024fb8bf8
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Gokul Murali
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,690 @@
1
+ # API Guard
2
+
3
+ [![Version](https://img.shields.io/gem/v/api_guard.svg?color=green)](https://rubygems.org/gems/api_guard_grape)
4
+ [![Build Status](https://github.com/prateeksinghbundela/api_guard_grape/workflows/build/badge.svg?branch=master)](https://github.com/prateeksinghbundela/api_guard_grape/actions?query=workflow%3Abuild)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/ced3e74a26a66ed915cb/maintainability)](https://codeclimate.com/github/prateeksinghbundela/api_guard_grape/maintainability)
6
+
7
+
8
+ [JSON Web Token (JWT)](https://jwt.io/) based authentication solution with token refreshing & blacklisting for APIs
9
+ built on Rails.
10
+
11
+ This is built using [Ruby JWT](https://github.com/jwt/ruby-jwt) gem. Currently API Guard supports only HS256 algorithm
12
+ for cryptographic signing.
13
+
14
+ ## Table of Contents
15
+
16
+ * [Installation](#installation)
17
+ * [Getting Started](#getting-started)
18
+ * [Creating User model](#creating-user-model)
19
+ * [Configuring Routes](#configuring-routes)
20
+ * [Registration](#registration)
21
+ * [Sign In (Getting JWT access token)](#sign-in-getting-jwt-access-token)
22
+ * [Authenticate API Request](#authenticate-api-request)
23
+ * [Refresh access token](#refresh-access-token)
24
+ * [Change password](#change-password)
25
+ * [Sign out](#sign-out)
26
+ * [Delete Account](#delete-account)
27
+ * [Configuration](#configuration)
28
+ * [Default configuration](#default-configuration)
29
+ * [Access token validity](#access-token-validity)
30
+ * [Access token signing secret](#access-token-signing-secret)
31
+ * [Invalidate tokens on password change](#invalidate-tokens-on-password-change)
32
+ * [Token refreshing](#token-refreshing)
33
+ * [Token blacklisting](#token-blacklisting)
34
+ * [Overriding defaults](#overriding-defaults)
35
+ * [Controllers](#controllers)
36
+ * [Routes](#routes)
37
+ * [Adding custom data in JWT token payload](#adding-custom-data-in-jwt-token-payload)
38
+ * [Override finding resource](#override-finding-resource)
39
+ * [Customizing / translating response messages using I18n](#customizing--translating-response-messages-using-i18n)
40
+ * [Testing](#testing)
41
+ * [Wiki](https://github.com/prateeksinghbundela/api_guard_grape/wiki)
42
+ * [Using API Guard with Devise](https://github.com/prateeksinghbundela/api_guard_grape/wiki/Using-API-Guard-with-Devise)
43
+ * [Contributing](#contributing)
44
+ * [License](#license)
45
+
46
+
47
+ ## Installation
48
+ Add this line to your application's Gemfile:
49
+
50
+ ```ruby
51
+ gem 'api_guard_grape'
52
+ ```
53
+
54
+ And then execute in your terminal:
55
+ ```bash
56
+ $ bundle install
57
+ ```
58
+
59
+ Or install it yourself as:
60
+ ```bash
61
+ $ gem install api_guard_grape
62
+ ```
63
+
64
+ ## Getting Started
65
+
66
+ Below steps are provided assuming the model in `User`.
67
+
68
+ ### Creating User model
69
+
70
+ Create a model for User with below command.
71
+
72
+ ```bash
73
+ $ rails generate model user name:string email:string:uniq password_digest:string
74
+ ```
75
+
76
+ Then, run migration to create the `users` table.
77
+
78
+ ```bash
79
+ $ rails db:migrate
80
+ ```
81
+
82
+ Add [has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password)
83
+ in `User` model for password authentication.
84
+
85
+ > Refer [this Wiki](https://github.com/prateeksinghbundela/api_guard_grape/wiki/Using-API-Guard-with-Devise#authentication) for configuring API Guard authentication to work with Devise instead of using `has_secure_password`.
86
+
87
+ ```ruby
88
+ class User < ApplicationRecord
89
+ has_secure_password
90
+ end
91
+ ```
92
+
93
+ Then, add `bcrypt` gem in your Gemfile which is used by
94
+ [has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password)
95
+ for encrypting password and authentication.
96
+
97
+ ```ruby
98
+ gem 'bcrypt', '~> 3.1.7'
99
+ ```
100
+
101
+ And then execute in your terminal:
102
+
103
+ ```bash
104
+ $ bundle install
105
+ ```
106
+
107
+ ### Configuring Routes
108
+
109
+ Add this line to the application routes (`config/routes.rb`) file:
110
+
111
+ ```ruby
112
+ api_guard_routes for: 'users'
113
+ ```
114
+
115
+ This will generate default routes such as sign up, sign in, sign out, token refresh, password change for User.
116
+
117
+ > Refer [this Wiki](https://github.com/prateeksinghbundela/api_guard_grape/wiki/Using-API-Guard-with-Devise#routes) for configuring API Guard routes to work with Devise.
118
+
119
+ ### Registration
120
+
121
+ This will create an user and responds with access token, refresh token and access token expiry in the response header.
122
+
123
+ Example request:
124
+
125
+ ```
126
+ # URL
127
+ POST "/users/sign_up"
128
+
129
+ # Request body
130
+ {
131
+ "email": "user@apiguard.com",
132
+ "password": "api_password",
133
+ "password_confirmation": "api_password"
134
+ }
135
+ ```
136
+
137
+ Example response body:
138
+
139
+ ```json
140
+ {
141
+ "status": "success",
142
+ "message": "Signed up successfully"
143
+ }
144
+ ```
145
+
146
+ Example response headers:
147
+
148
+ ```
149
+ Access-Token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1NDY3MDgwMjAsImlhdCI6MTU0NjcwNjIyMH0.F_JM7fUcKEAq9ZxXMxNb3Os-WeY-tuRYQnKXr_bWo5E
150
+ Refresh-Token: Iy9s0S4Lf7Xh9MbFFBdxkw
151
+ Expire-At: 1546708020
152
+ ```
153
+
154
+ The access token will only be valid till the expiry time. After the expiry you need to
155
+ [refresh the token](#refresh-access-token) and get new access token and refresh token.
156
+
157
+ You can customize the parameters of this API by [overriding the controller](#controllers) code if needed.
158
+
159
+ ### Sign In (Getting JWT access token)
160
+
161
+ This will authenticate the user with email and password and respond with access token, refresh token and access token
162
+ expiry in the response header.
163
+
164
+ >To make this work, the resource model (User) should have an `authenticate` method as available in
165
+ [has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password).
166
+ You can use [has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password)
167
+ or your own logic to authenticate the user in `authenticate` method.
168
+
169
+ Example request:
170
+
171
+ ```
172
+ # URL
173
+ POST "/users/sign_in"
174
+
175
+ # Request body
176
+ {
177
+ "email": "user@apiguard.com",
178
+ "password": "api_password"
179
+ }
180
+ ```
181
+
182
+ Example response body:
183
+
184
+ ```json
185
+ {
186
+ "status": "success",
187
+ "message": "Signed in successfully"
188
+ }
189
+ ```
190
+
191
+ Example response headers:
192
+
193
+ The response headers for this request will be same as [registration API](#registration).
194
+
195
+ You can customize the parameters of this API by [overriding the controller](#controllers) code if needed.
196
+
197
+ ### Authenticate API Request
198
+
199
+ To authenticate the API request just add this before_action in the controller:
200
+
201
+ ```ruby
202
+ before_action :authenticate_and_set_user
203
+ ```
204
+
205
+ Send the access token got in sign in API in the Authorization header in the API request as below.
206
+ Also, make sure you add "Bearer" before the access token in the header value.
207
+
208
+ ```
209
+ Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1NDY3MDgwMjAsImlhdCI6MTU0NjcwNjIyMH0.F_JM7fUcKEAq9ZxXMxNb3Os-WeY-tuRYQnKXr_bWo5E
210
+ ```
211
+
212
+ Then, you can get the current authenticated user using below method:
213
+
214
+ ```ruby
215
+ current_user
216
+ ```
217
+
218
+ and also, using below instance variable:
219
+
220
+ ```ruby
221
+ @current_user
222
+ ```
223
+
224
+ >**Note:** Replace `_user` with your model name if your model is not User.
225
+
226
+ ### Refresh access token
227
+
228
+ This will work only if token refreshing configured for the resource.
229
+ Please see [token refreshing](#token-refreshing) for details about configuring token refreshing.
230
+
231
+ Once the access token expires it won't work and the `authenticate_and_set_user` method used in before_action in
232
+ controller will respond with 401 (Unauthenticated).
233
+
234
+ To refresh the expired access token and get new access and refresh token you can use this request
235
+ with both access token and request token (which you got in sign in API) in the request header.
236
+
237
+ Example request:
238
+
239
+ ```
240
+ # URL
241
+ POST "/users/tokens"
242
+
243
+ # Request header
244
+ Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1NDY3MDgwMjAsImlhdCI6MTU0NjcwNjIyMH0.F_JM7fUcKEAq9ZxXMxNb3Os-WeY-tuRYQnKXr_bWo5E
245
+ Refresh-Token: Iy9s0S4Lf7Xh9MbFFBdxkw
246
+ ```
247
+
248
+ Example response body:
249
+
250
+ ```json
251
+ {
252
+ "status": "success",
253
+ "message": "Token refreshed successfully"
254
+ }
255
+ ```
256
+
257
+ Example response headers:
258
+
259
+ The response headers for this request will be same as [registration API](#registration).
260
+
261
+ ### Change password
262
+
263
+ To change password of an user you can use this request with the access token in the header and new
264
+ password in the body.
265
+
266
+ By default, changing password will invalidate all old access tokens and refresh tokens generated for this user and
267
+ responds with new access token and refresh token.
268
+
269
+ Example request:
270
+
271
+ ```
272
+ # URL
273
+ PATCH "/users/passwords"
274
+
275
+ # Request header
276
+ Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1NDY3MDgwMjAsImlhdCI6MTU0NjcwNjIyMH0.F_JM7fUcKEAq9ZxXMxNb3Os-WeY-tuRYQnKXr_bWo5E
277
+
278
+ # Request body
279
+ {
280
+ "password": "api_password_new",
281
+ "password_confirmation": "api_password_new"
282
+ }
283
+ ```
284
+
285
+ Example response body:
286
+
287
+ ```json
288
+ {
289
+ "status": "success",
290
+ "message": "Password changed successfully"
291
+ }
292
+ ```
293
+
294
+ Example response headers:
295
+
296
+ The response headers for this request will be same as [registration API](#registration).
297
+
298
+ ### Sign out
299
+
300
+ You can use this request to sign out an user. This will blacklist the current access token from future use if
301
+ [token blacklisting](#token-blacklisting) configured.
302
+
303
+ Example request:
304
+
305
+ ```
306
+ # URL
307
+ DELETE "/users/sign_out"
308
+
309
+ # Request header
310
+ Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1NDY3MDgwMjAsImlhdCI6MTU0NjcwNjIyMH0.F_JM7fUcKEAq9ZxXMxNb3Os-WeY-tuRYQnKXr_bWo5E
311
+ ```
312
+
313
+ Example response:
314
+
315
+ ```json
316
+ {
317
+ "status": "success",
318
+ "message": "Signed out successfully"
319
+ }
320
+ ```
321
+
322
+ ### Delete account
323
+
324
+ You can use this request to delete an user. This will delete the user and its associated refresh tokens.
325
+
326
+ Example request:
327
+
328
+ ```
329
+ # URL
330
+ DELETE "/users/delete"
331
+
332
+ # Request header
333
+ Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1NDY3MDgwMjAsImlhdCI6MTU0NjcwNjIyMH0.F_JM7fUcKEAq9ZxXMxNb3Os-WeY-tuRYQnKXr_bWo5E
334
+ ```
335
+
336
+ Example response:
337
+
338
+ ```json
339
+ {
340
+ "status": "success",
341
+ "message": "Account deleted successfully"
342
+ }
343
+ ```
344
+
345
+ ## Configuration
346
+
347
+ To configure the API Guard you need to first create an initializer using
348
+
349
+ ```bash
350
+ $ rails generate api_guard:initializer
351
+ ```
352
+
353
+ This will generate an initializer named **api_guard.rb** in your app **config/initializers** directory with default
354
+ configurations.
355
+
356
+ ### Default configuration
357
+
358
+ **config/initializers/api_guard.rb**
359
+
360
+ ```ruby
361
+ ApiGuard.setup do |config|
362
+ # Validity of the JWT access token
363
+ # Default: 1 day
364
+ # config.token_validity = 1.day
365
+
366
+ # Secret key for signing (encoding & decoding) the JWT access token
367
+ # Default: 'secret_key_base' from Rails secrets
368
+ # config.token_signing_secret = 'my_signing_secret'
369
+
370
+ # Invalidate old tokens on changing the password
371
+ # Default: false
372
+ # config.invalidate_old_tokens_on_password_change = false
373
+
374
+ # Blacklist JWT access token after refreshing
375
+ # Default: false
376
+ # config.blacklist_token_after_refreshing = false
377
+ end
378
+ ```
379
+
380
+ ### Access token validity
381
+
382
+ By default, the validity of the JWT access token is 1 day from the creation. Override this by configuring `token_validity`
383
+
384
+ ```ruby
385
+ config.token_validity = 1.hour # Set one hour validity for access tokens
386
+ ```
387
+
388
+ On accessing the authenticated API with expired access token, API Guard will respond 401 (Unauthenticated) with message
389
+ "Access token expired".
390
+
391
+ ### Access token signing secret
392
+
393
+ By default, the `secret_key_base` from the Rails secrets will be used for signing (encoding & decoding) the JWT access token.
394
+ Override this by configuring `token_signing_secret`
395
+
396
+ ```ruby
397
+ config.token_signing_secret = 'my_signing_secret'
398
+ ```
399
+
400
+ >**Note:** Avoid committing this token signing secret in your version control (GIT) and always keep this secure. As,
401
+ >exposing this allow anyone to generate JWT access token and give full access to APIs. Better way is storing this value
402
+ >in environment variable or in encrypted secrets (Rails 5.2+)
403
+
404
+ ### Invalidate tokens on password change
405
+
406
+ By default, API Guard will not invalidate old JWT access tokens on changing password. If you need, you can enable it by
407
+ configuring `invalidate_old_tokens_on_password_change` to `true`.
408
+
409
+ >**Note:** To make this work, a column named `token_issued_at` with datatype `datetime` is needed in the resource table.
410
+
411
+ ```ruby
412
+ config.invalidate_old_tokens_on_password_change = true
413
+ ```
414
+
415
+ If your app allows multiple logins then, you must set this value to `true` so that, this prevent access for all logins
416
+ (access tokens) on changing the password.
417
+
418
+ ### Token refreshing
419
+
420
+ To include token refreshing in your application you need to create a table to store the refresh tokens.
421
+
422
+ Use below command to create a model `RefeshToken` with columns to store the token and the user reference
423
+
424
+ ```bash
425
+ $ rails generate model refresh_token token:string:uniq user:references
426
+ ```
427
+
428
+ Then, run migration to create the `refresh_tokens` table
429
+
430
+ ```bash
431
+ $ rails db:migrate
432
+ ```
433
+
434
+ >**Note:** Replace `user` in the above command with your model name if your model is not User.
435
+
436
+ After creating model and table for refresh token configure the association in the resource model using
437
+ `api_guard_associations` method
438
+
439
+ ```ruby
440
+ class User < ApplicationRecord
441
+ api_guard_associations refresh_token: 'refresh_tokens'
442
+ has_many :refresh_tokens, dependent: :delete_all
443
+ end
444
+ ```
445
+
446
+ If you also have token blacklisting enabled you need to specify both associations as below
447
+
448
+ ```ruby
449
+ api_guard_associations refresh_token: 'refresh_tokens', blacklisted_token: 'blacklisted_tokens'
450
+ ```
451
+
452
+ ### Token blacklisting
453
+
454
+ To include token blacklisting in your application you need to create a table to store the blacklisted tokens. This will be
455
+ used to blacklist a JWT access token from future use. The access token will be blacklisted on successful sign out of the
456
+ resource.
457
+
458
+ Use below command to create a model `BlacklistedToken` with columns to store the token and the user reference
459
+
460
+ ```bash
461
+ $ rails generate model blacklisted_token token:string user:references expire_at:datetime
462
+ ```
463
+
464
+ Then, run migration to create the `blacklisted_tokens` table
465
+
466
+ ```bash
467
+ $ rails db:migrate
468
+ ```
469
+
470
+ >**Note:** Replace `user` in the above command with your model name if your model is not User.
471
+
472
+ After creating model and table for blacklisted token configure the association in the resource model using
473
+ `api_guard_associations` method
474
+
475
+ ```ruby
476
+ class User < ApplicationRecord
477
+ api_guard_associations blacklisted_token: 'blacklisted_tokens'
478
+ has_many :blacklisted_tokens, dependent: :delete_all
479
+ end
480
+ ```
481
+
482
+ If you also have token refreshing enabled you need to specify both associations as below
483
+
484
+ ```ruby
485
+ api_guard_associations refresh_token: 'refresh_tokens', blacklisted_token: 'blacklisted_tokens'
486
+ ```
487
+
488
+ And, as this creates rows in `blacklisted_tokens` table you need to have a mechanism to delete the expired blacklisted
489
+ tokens to prevent this table from growing. One option is to have a CRON job to run a task daily that deletes the
490
+ blacklisted tokens that are expired i.e. `expire_at < DateTime.now`.
491
+
492
+ **Blacklisting after refreshing token**
493
+
494
+ By default, the JWT access token will not be blacklisted on refreshing the JWT access token. To enable this, you can
495
+ configure it in API Guard initializer as below,
496
+
497
+ ```ruby
498
+ config.blacklist_token_after_refreshing = true
499
+ ```
500
+
501
+ ## Overriding defaults
502
+
503
+ ### Controllers
504
+
505
+ You can override the default API Guard controllers and customize the code as your need by generating the controllers in
506
+ your app
507
+
508
+ ```bash
509
+ $ rails generate api_guard:controllers users
510
+ ```
511
+
512
+ In above command `users` is the scope of the controllers. If needed, you can replace `users` with your own scope.
513
+
514
+ This will generate all default controllers for `users` in the directory **app/controllers/users**.
515
+
516
+ Then, configure this controller in the routes
517
+
518
+ ```ruby
519
+ api_guard_routes for: 'users', controller: {
520
+ registration: 'users/registration',
521
+ authentication: 'users/authentication',
522
+ passwords: 'users/passwords',
523
+ tokens: 'users/tokens'
524
+ }
525
+ ```
526
+
527
+ You can also specify the controllers that you need to generate using `-c` or `--controllers` option.
528
+
529
+ ```bash
530
+ $ rails generate api_guard:controllers users -c registration authentication
531
+ ```
532
+
533
+ >**Available controllers:** registration, authentication, tokens, passwords
534
+
535
+ ### Routes
536
+
537
+ You can skip specific controller routes generated by API Guard
538
+
539
+ ```ruby
540
+ api_guard_routes for: 'users', except: [:registration]
541
+ ```
542
+
543
+ Above config will skip registration related API Guard controller routes for the resource user.
544
+
545
+
546
+ You can also specify only the controller routes you need,
547
+
548
+ ```ruby
549
+ api_guard_routes for: 'users', only: [:authentication]
550
+ ```
551
+
552
+ >**Available controllers:** registration, authentication, tokens, passwords
553
+
554
+ **Customizing the route path:**
555
+
556
+ You can customize the path of the default routes of the API Guard using the `api_guard_scope` as below,
557
+
558
+ ```ruby
559
+ api_guard_routes for: 'users', except: [:registration]
560
+
561
+ api_guard_scope 'users' do
562
+ post 'account/create' => 'api_guard/registration#create'
563
+ delete 'account/delete' => 'api_guard/registration#destroy'
564
+ end
565
+ ```
566
+
567
+ Above configuration will replace default registration routes `users/sign_up` & `users/delete` with `account/create` &
568
+ `account/delete`
569
+
570
+ ### Adding custom data in JWT token payload
571
+
572
+ You can add custom data in the JWT token payload in the format of Hash and use the data after decoding the token on
573
+ every request.
574
+
575
+ To add custom data, you need to create an instance method `jwt_token_payload` in the resource model as below which
576
+ should return a Hash,
577
+
578
+ ```ruby
579
+ class User < ApplicationRecord
580
+ def jwt_token_payload
581
+ { custom_key: 'value' }
582
+ end
583
+ end
584
+ ```
585
+
586
+ API Guard will add the hash returned by this method to the JWT token payload in addition to the default payload values.
587
+ This data (including default payload values) will be available in the instance variable `@decoded_token` on each request
588
+ if the token has been successfully decoded. You can access the values as below,
589
+
590
+ ```ruby
591
+ @decoded_token[:custom_key]
592
+ ```
593
+
594
+ ### Override finding resource
595
+
596
+ By default, API Guard will try to find the resource by it's `id`. If you wish to override this default behavior, you can
597
+ do it by creating a method `find_resource_from_token` in the specific controller or in `ApplicationController` as you
598
+ need.
599
+
600
+ **Adding custom logic in addition to the default logic:**
601
+ ```ruby
602
+ def find_resource_from_token(resource_class)
603
+ user = super # This will call the actual method defined in API Guard
604
+ user if user&.active?
605
+ end
606
+ ```
607
+
608
+ **Using custom query to find the user from the token:**
609
+ ```ruby
610
+ def find_resource_from_token(resource_class)
611
+ resource_id = @decoded_token[:"#{@resource_name}_id"]
612
+ resource_class.find_by(id: resource_id, status: 'active') if resource_id
613
+ end
614
+ ```
615
+
616
+ This method has an argument `resource_class` which is the class (model) of the current resource (`User`).
617
+ This method should return a resource object to successfully authenticate the request or `nil` to respond with 401.
618
+
619
+ You can also use the [custom data](#adding-custom-data-in-jwt-token-payload) added in the JWT token payload using
620
+ `@decoded_token` instance variable and customize the logic as you need.
621
+
622
+ ### Customizing / translating response messages using I18n
623
+
624
+ API Guard uses [I18n](https://guides.rubyonrails.org/i18n.html) for success and error messages. You can create your own
625
+ locale file and customize the messages for any language.
626
+
627
+ ```yaml
628
+ en:
629
+ api_guard:
630
+ authentication:
631
+ signed_in: 'Signed in successfully'
632
+ signed_out: 'Signed out successfully'
633
+ ```
634
+
635
+ You can find the complete list of available keys in this file:
636
+ https://github.com/prateeksinghbundela/api_guard_grape/blob/master/config/locales/en.yml
637
+
638
+ ## Testing
639
+
640
+ API Guard comes with helper for creating JWT access token and refresh token for the resource which you can use it for
641
+ testing the controllers of your application.
642
+
643
+ For using it, just include the helper in your test framework.
644
+
645
+ **RSpec**
646
+
647
+ If you're using RSpec as your test framework then include the helper in **spec/rails_helper.rb** file
648
+
649
+ ```ruby
650
+ RSpec.configure do |config|
651
+ config.include ApiGuard::Test::ControllerHelper
652
+ end
653
+ ```
654
+
655
+ **Minitest**
656
+
657
+ If you're using Minitest as your test framework then include the helper in your test file
658
+
659
+ ```ruby
660
+ include ApiGuard::Test::ControllerHelper
661
+ ```
662
+
663
+ After including the helper, you can use this method to create the JWT access token and refresh token for the resource
664
+
665
+ ```ruby
666
+ jwt_and_refresh_token(user, 'user')
667
+ ```
668
+
669
+ Where the first argument is the resource(User) object and the second argument is the resource name which is `user`.
670
+
671
+ This method will return two values which is access token and refresh token.
672
+
673
+ If you need expired JWT access token for testing you can pass the third optional argument value as `true`
674
+
675
+ ```ruby
676
+ jwt_and_refresh_token(user, 'user', true)
677
+ ```
678
+
679
+ Then, you can set the access token and refresh token in appropriate request header on each test request.
680
+
681
+ ## Contributing
682
+
683
+ Bug reports and pull requests are welcome on GitHub at https://github.com/prateeksinghbundela/api_guard_grape.
684
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
685
+ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
686
+
687
+ ## License
688
+
689
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
690
+