api_guard_grape 0.5.1

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.
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
+