grape-jwt-authentication 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +43 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +114 -0
- data/LICENSE +21 -0
- data/README.md +391 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/doc/assets/logo.png +0 -0
- data/doc/assets/project.png +0 -0
- data/doc/assets/project.xcf +0 -0
- data/grape-jwt-authentication.gemspec +39 -0
- data/lib/grape/jwt/authentication.rb +64 -0
- data/lib/grape/jwt/authentication/configuration.rb +130 -0
- data/lib/grape/jwt/authentication/jwt.rb +112 -0
- data/lib/grape/jwt/authentication/jwt_handler.rb +118 -0
- data/lib/grape/jwt/authentication/rsa_public_key.rb +126 -0
- data/lib/grape/jwt/authentication/version.rb +9 -0
- metadata +261 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6a78c43fa11b24e40395c34bbc802f61c6e4646c
|
4
|
+
data.tar.gz: ca386d7ac9298045d93e38b0c6df2c3e8ab1dcae
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b234415911e6f3f2820d9511af016e290ed4723521374913d9cb5b5e05925722a9222f48016c7f4a75f88ee30aa901aaa702f8699e86792e4ed9d58fab439c6
|
7
|
+
data.tar.gz: 1557a1c9a4fc4acb8cf77be68fbaf4f5417753bc5e859917508bd334e36ca9449e9c483119b009158f9d0ac4202413a372ed2c4638d45444e0e9d6ce9594139a
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require: rubocop-rspec
|
2
|
+
|
3
|
+
Rails:
|
4
|
+
Enabled: true
|
5
|
+
|
6
|
+
Documentation:
|
7
|
+
Enabled: true
|
8
|
+
|
9
|
+
AllCops:
|
10
|
+
DisplayCopNames: true
|
11
|
+
TargetRubyVersion: 2.3
|
12
|
+
Exclude:
|
13
|
+
- db/schema.rb
|
14
|
+
- bin/**/*
|
15
|
+
- db/migrate/**/*
|
16
|
+
- vendor/cache/**/*
|
17
|
+
- vendor/bundle/**/*
|
18
|
+
- build/**/*
|
19
|
+
|
20
|
+
Metrics/BlockLength:
|
21
|
+
Exclude:
|
22
|
+
# Because of the Grape DSL
|
23
|
+
- lib/**/*.rb
|
24
|
+
- Rakefile
|
25
|
+
- grape-jwt-authentication.gemspec
|
26
|
+
- spec/**/*.rb
|
27
|
+
- '**/*.rake'
|
28
|
+
|
29
|
+
# Document all the things.
|
30
|
+
Style/DocumentationMethod:
|
31
|
+
Enabled: true
|
32
|
+
RequireForNonPublicMethods: true
|
33
|
+
|
34
|
+
# It's a deliberate idiom in RSpec.
|
35
|
+
# See: https://github.com/bbatsov/rubocop/issues/4222
|
36
|
+
Lint/AmbiguousBlockAssociation:
|
37
|
+
Exclude:
|
38
|
+
- "spec/**/*"
|
39
|
+
|
40
|
+
# Because +expect_any_instance_of().to have_received()+ is not
|
41
|
+
# supported with the +with(hash_including)+ matchers
|
42
|
+
RSpec/MessageSpies:
|
43
|
+
EnforcedStyle: receive
|
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
env:
|
2
|
+
global:
|
3
|
+
- CC_TEST_REPORTER_ID=6e5d2de1ccc0412cdc8d01fdddc560fe3051b14f1c15fea55b0d6e32e27a81cf
|
4
|
+
|
5
|
+
sudo: false
|
6
|
+
language: ruby
|
7
|
+
rvm:
|
8
|
+
- 2.2
|
9
|
+
- 2.3
|
10
|
+
- 2.4
|
11
|
+
|
12
|
+
before_install: gem install bundler
|
13
|
+
|
14
|
+
before_script:
|
15
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
16
|
+
- chmod +x ./cc-test-reporter
|
17
|
+
- ./cc-test-reporter before-build
|
18
|
+
|
19
|
+
after_script:
|
20
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
grape-jwt-authentication (1.0.1)
|
5
|
+
activesupport (>= 3.2.0)
|
6
|
+
grape (~> 1.0)
|
7
|
+
httparty
|
8
|
+
jwt (~> 2.1)
|
9
|
+
recursive-open-struct (~> 1.0)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activesupport (5.1.4)
|
15
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
+
i18n (~> 0.7)
|
17
|
+
minitest (~> 5.1)
|
18
|
+
tzinfo (~> 1.1)
|
19
|
+
addressable (2.5.2)
|
20
|
+
public_suffix (>= 2.0.2, < 4.0)
|
21
|
+
axiom-types (0.1.1)
|
22
|
+
descendants_tracker (~> 0.0.4)
|
23
|
+
ice_nine (~> 0.11.0)
|
24
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
25
|
+
builder (3.2.3)
|
26
|
+
coercible (1.0.0)
|
27
|
+
descendants_tracker (~> 0.0.1)
|
28
|
+
concurrent-ruby (1.0.5)
|
29
|
+
crack (0.4.3)
|
30
|
+
safe_yaml (~> 1.0.0)
|
31
|
+
descendants_tracker (0.0.4)
|
32
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
33
|
+
diff-lcs (1.3)
|
34
|
+
docile (1.1.5)
|
35
|
+
equalizer (0.0.11)
|
36
|
+
grape (1.0.1)
|
37
|
+
activesupport
|
38
|
+
builder
|
39
|
+
mustermann-grape (~> 1.0.0)
|
40
|
+
rack (>= 1.3.0)
|
41
|
+
rack-accept
|
42
|
+
virtus (>= 1.0.0)
|
43
|
+
hashdiff (0.3.7)
|
44
|
+
httparty (0.15.6)
|
45
|
+
multi_xml (>= 0.5.2)
|
46
|
+
i18n (0.9.1)
|
47
|
+
concurrent-ruby (~> 1.0)
|
48
|
+
ice_nine (0.11.2)
|
49
|
+
json (2.1.0)
|
50
|
+
jwt (2.1.0)
|
51
|
+
minitest (5.10.3)
|
52
|
+
multi_xml (0.6.0)
|
53
|
+
mustermann (1.0.1)
|
54
|
+
mustermann-grape (1.0.0)
|
55
|
+
mustermann (~> 1.0.0)
|
56
|
+
public_suffix (3.0.1)
|
57
|
+
rack (2.0.3)
|
58
|
+
rack-accept (0.4.5)
|
59
|
+
rack (>= 0.4)
|
60
|
+
rack-test (0.8.2)
|
61
|
+
rack (>= 1.0, < 3)
|
62
|
+
rake (10.5.0)
|
63
|
+
recursive-open-struct (1.0.5)
|
64
|
+
rspec (3.7.0)
|
65
|
+
rspec-core (~> 3.7.0)
|
66
|
+
rspec-expectations (~> 3.7.0)
|
67
|
+
rspec-mocks (~> 3.7.0)
|
68
|
+
rspec-core (3.7.0)
|
69
|
+
rspec-support (~> 3.7.0)
|
70
|
+
rspec-expectations (3.7.0)
|
71
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
72
|
+
rspec-support (~> 3.7.0)
|
73
|
+
rspec-mocks (3.7.0)
|
74
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
75
|
+
rspec-support (~> 3.7.0)
|
76
|
+
rspec-support (3.7.0)
|
77
|
+
safe_yaml (1.0.4)
|
78
|
+
simplecov (0.15.1)
|
79
|
+
docile (~> 1.1.0)
|
80
|
+
json (>= 1.8, < 3)
|
81
|
+
simplecov-html (~> 0.10.0)
|
82
|
+
simplecov-html (0.10.2)
|
83
|
+
thread_safe (0.3.6)
|
84
|
+
timecop (0.9.1)
|
85
|
+
tzinfo (1.2.4)
|
86
|
+
thread_safe (~> 0.1)
|
87
|
+
vcr (3.0.3)
|
88
|
+
virtus (1.0.5)
|
89
|
+
axiom-types (~> 0.1)
|
90
|
+
coercible (~> 1.0)
|
91
|
+
descendants_tracker (~> 0.0, >= 0.0.3)
|
92
|
+
equalizer (~> 0.0, >= 0.0.9)
|
93
|
+
webmock (3.1.1)
|
94
|
+
addressable (>= 2.3.6)
|
95
|
+
crack (>= 0.3.2)
|
96
|
+
hashdiff
|
97
|
+
|
98
|
+
PLATFORMS
|
99
|
+
ruby
|
100
|
+
|
101
|
+
DEPENDENCIES
|
102
|
+
bundler (~> 1.16)
|
103
|
+
grape-jwt-authentication!
|
104
|
+
rack (~> 2.0)
|
105
|
+
rack-test (~> 0.8.2)
|
106
|
+
rake (~> 10.0)
|
107
|
+
rspec (~> 3.0)
|
108
|
+
simplecov (~> 0.15)
|
109
|
+
timecop (~> 0.9.1)
|
110
|
+
vcr (~> 3.0)
|
111
|
+
webmock (~> 3.1)
|
112
|
+
|
113
|
+
BUNDLED WITH
|
114
|
+
1.16.0
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 HAUSGOLD | talocasa GmbH
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,391 @@
|
|
1
|
+
![grape-jwt-authentication](doc/assets/project.png)
|
2
|
+
|
3
|
+
[![Build Status](https://api.travis-ci.org/hausgold/grape-jwt-authentication.svg)](https://travis-ci.org/hausgold/grape-jwt-authentication)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/grape-jwt-authentication.svg)](https://badge.fury.io/rb/grape-jwt-authentication)
|
5
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/446f3eff18bebff9c174/maintainability)](https://codeclimate.com/github/hausgold/grape-jwt-authentication/maintainability)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/hausgold/grape-jwt-authentication/badges/coverage.svg)](https://codeclimate.com/github/hausgold/grape-jwt-authentication/coverage)
|
7
|
+
|
8
|
+
This gem is dedicated to easily integrate a JWT authentication to your
|
9
|
+
[Grape](https://github.com/ruby-grape/grape) API. The real authentication
|
10
|
+
functionality must be provided by the user and this makes this gem highy
|
11
|
+
flexible on the JWT verification level.
|
12
|
+
|
13
|
+
- [Installation](#installation)
|
14
|
+
- [Usage](#usage)
|
15
|
+
- [Grape API](#grape-api)
|
16
|
+
- [Configuration](#configuration)
|
17
|
+
- [Authenticator](#authenticator)
|
18
|
+
- [Malformed token handling](#malformed-token-handling)
|
19
|
+
- [Failed authentication handling](#failed-authentication-handling)
|
20
|
+
- [RSA public key helper](#rsa-public-key-helper)
|
21
|
+
- [RSA public key location (URL)](#rsa-public-key-location-url)
|
22
|
+
- [RSA public key caching](#rsa-public-key-caching)
|
23
|
+
- [RSA public key cache expiration](#rsa-public-key-cache-expiration)
|
24
|
+
- [JWT instance helper](#jwt-instance-helper)
|
25
|
+
- [Issuer verification](#issuer-verification)
|
26
|
+
- [Beholder (audience) verification](#beholder-audience-verification)
|
27
|
+
- [Custom JWT verification options](#custom-jwt-verification-options)
|
28
|
+
- [Custom JWT verification key](#custom-jwt-verification-key)
|
29
|
+
- [Per-API configuration](#per-api-configuration)
|
30
|
+
- [Full RSA256 example](#full-rsa256-example)
|
31
|
+
- [Development](#development)
|
32
|
+
- [Contributing](#contributing)
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
|
36
|
+
Add this line to your application's Gemfile:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
gem 'grape-jwt-authentication'
|
40
|
+
```
|
41
|
+
|
42
|
+
And then execute:
|
43
|
+
|
44
|
+
```bash
|
45
|
+
$ bundle
|
46
|
+
```
|
47
|
+
|
48
|
+
Or install it yourself as:
|
49
|
+
|
50
|
+
```bash
|
51
|
+
$ gem install grape-jwt-authentication
|
52
|
+
```
|
53
|
+
|
54
|
+
## Usage
|
55
|
+
|
56
|
+
### Grape API
|
57
|
+
|
58
|
+
You can enable the JWT authentication on any Grape API you like. This includes
|
59
|
+
specific endpoints or a whole API. Just include the
|
60
|
+
`Grape::Jwt::Authentication` module and configure it the way you like.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
module UserApi
|
64
|
+
class ApiV1 < Grape::API
|
65
|
+
# All your fancy Grape API stuff [..]
|
66
|
+
version 'v1', using: :path
|
67
|
+
|
68
|
+
# Enable JWT authentication on this API
|
69
|
+
include Grape::Jwt::Authentication
|
70
|
+
auth :jwt
|
71
|
+
end
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
### Configuration
|
76
|
+
|
77
|
+
This gem is quite customizable and flexible to fulfill your needs. You can make
|
78
|
+
use of some parts and leave other if you do not care about them. We are not
|
79
|
+
going to force the way how to verify JWT or work with them. Here comes a
|
80
|
+
overview of the configurations you can do.
|
81
|
+
|
82
|
+
#### Authenticator
|
83
|
+
|
84
|
+
The authenticator function which must be defined by the user to verify the
|
85
|
+
given JSON Web Token. Here comes all your logic to lookup the related user on
|
86
|
+
your database, the token claim verification and/or the token cryptographic
|
87
|
+
signing. The function must return true or false to indicate the validity of the
|
88
|
+
token.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
Grape::Jwt::Authentication.configure do |conf|
|
92
|
+
conf.authenticator = proc do |token|
|
93
|
+
# Verify the token the way you like. (true, false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
#### Malformed token handling
|
99
|
+
|
100
|
+
Whenever the given value on the `Authorization` header is not a valid Bearer
|
101
|
+
authentication scheme or the token itself is not a valid JSON Web Token, this
|
102
|
+
user defined function will be called. You can add custom handling of this
|
103
|
+
situations, like responding a different HTTP status code, or a more detailed
|
104
|
+
response body. By default the Rack stack will be interrupted and a response
|
105
|
+
with the `400 Bad Request` status code will be send to the client. The raw
|
106
|
+
token (value of the `Authorization` header) and the Rack app will be injected
|
107
|
+
to your function for maximum flexibility.
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
Grape::Jwt::Authentication.configure do |conf|
|
111
|
+
conf.malformed_auth_handler = proc do |raw_token, app|
|
112
|
+
# Do your own error handling. (Rack interface)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
#### Failed authentication handling
|
118
|
+
|
119
|
+
When the client sends a corrected formatted JSON Web Token with the Bearer
|
120
|
+
authentication scheme within the `Authorization` header and your authenticator
|
121
|
+
fails for some reason (token claims, wrong audience, bad subject, expired
|
122
|
+
token, wrong cryptographic signing etc), this function is called to handle the
|
123
|
+
bad authentication. By default the Rack stack will be interrupted and a
|
124
|
+
response with the `401 Unauthorized` status code will be send to the client.
|
125
|
+
You can customize this the way you like and send different error codes, or
|
126
|
+
handle the error completely different. The parsed JSON Web Token and the Rack
|
127
|
+
app will be injected to your function to allow any customized error handling.
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
Grape::Jwt::Authentication.configure do |conf|
|
131
|
+
conf.failed_auth_handler = proc do |token, app|
|
132
|
+
# Do your own error handling. (Rack interface)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
#### RSA public key helper
|
138
|
+
|
139
|
+
We provide a straightforward solution to deal with the provision of RSA public
|
140
|
+
keys. Somethimes you want to distribute them by file to each machine and have
|
141
|
+
a local access, and somethimes you provide an endpoint on your identity
|
142
|
+
provider to fetch the RSA public key via HTTP/HTTPS. The `RsaPublicKey` class
|
143
|
+
helps you to fulfill this task easily.
|
144
|
+
|
145
|
+
**Heads up!** You can skip this if you do not care about RSA verification or
|
146
|
+
have your own mechanism.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
# Get your public key, by using the global configuration
|
150
|
+
public_key = Grape::Jwt::Authentication::RsaPublicKey.fetch
|
151
|
+
# => OpenSSL::PKey::RSA
|
152
|
+
|
153
|
+
# Using a local configuration
|
154
|
+
fetcher = Grape::Jwt::Authentication::RsaPublicKey.instance
|
155
|
+
fetcher.url = 'https://your.identity.provider/rsa_public_key'
|
156
|
+
public_key = fetcher.fetch
|
157
|
+
# => OpenSSL::PKey::RSA
|
158
|
+
```
|
159
|
+
|
160
|
+
The following examples show you how to configure the
|
161
|
+
`Grape::Jwt::Authentication::RsaPublicKey` class the global way. This is useful
|
162
|
+
for a shared initializer place.
|
163
|
+
|
164
|
+
##### RSA public key location (URL)
|
165
|
+
|
166
|
+
Whenever you want to use the `RsaPublicKey` class you configure the default URL
|
167
|
+
on the singleton instance, or use the gem configure method and set it up
|
168
|
+
accordingly. We allow the fetch of the public key from a remote server
|
169
|
+
(HTTP/HTTPS) or from a local file which is accessible by the ruby process.
|
170
|
+
Specify the URL or the local path here. Not specified by default.
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
Grape::Jwt::Authentication.configure do |conf|
|
174
|
+
# Local file
|
175
|
+
conf.rsa_public_key_url = '/tmp/jwt_rsa.pub'
|
176
|
+
# Remote URL
|
177
|
+
conf.rsa_public_key_url = 'https://your.identity.provider/rsa_public_key'
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
##### RSA public key caching
|
182
|
+
|
183
|
+
You can configure the `RsaPublickey` class to enable/disable caching. For a
|
184
|
+
remote public key location it is handy to cache the result for some time to
|
185
|
+
keep the traffic low to the resource server. For a local file you can skip
|
186
|
+
this. Disabled by default.
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
Grape::Jwt::Authentication.configure do |conf|
|
190
|
+
conf.rsa_public_key_caching = true
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
##### RSA public key cache expiration
|
195
|
+
|
196
|
+
When you make use of the cache of the `RsaPublicKey` class you can fine tune
|
197
|
+
the expiration time. The RSA public key from your identity
|
198
|
+
provider should not change this frequent, so a cache for at least one hour is
|
199
|
+
fine. You should not set it lower than one minute. Keep this setting in mind
|
200
|
+
when you change keys. Your infrastructure could be inoperable for this
|
201
|
+
configured time. One hour by default.
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
Grape::Jwt::Authentication.configure do |conf|
|
205
|
+
conf.rsa_public_key_expiration = 1.hour
|
206
|
+
end
|
207
|
+
```
|
208
|
+
|
209
|
+
#### JWT instance helper
|
210
|
+
|
211
|
+
We ship a little wrapper class to ease the validation of JSON Web Tokens with
|
212
|
+
the help of the great [ruby-jwt](https://github.com/jwt/ruby-jwt) library. This
|
213
|
+
wrapper class provides some helpers like `#access_token?`, `#refresh_token?` or
|
214
|
+
`#expires_at` which returns a ActiveSupport time-zoned representation of the
|
215
|
+
token expiration timestamp. It is initially opinionated to RSA verification,
|
216
|
+
but can be tuned to verify HMAC or ECDSA signed tokens. It integrated well with
|
217
|
+
the `RsaPublicKey` fetcher class. (by default)
|
218
|
+
|
219
|
+
**Heads up!** You can skip this if you have your own JWT verification mechanism.
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
# A raw JWT (no signing, payload: {test: true})
|
223
|
+
raw_token = 'eyJ0eXAiOiJKV1QifQ.eyJ0ZXN0Ijp0cnVlfQ.'
|
224
|
+
|
225
|
+
# Parse the raw token and create a instance of it
|
226
|
+
token = Grape::Jwt::Authentication::Jwt.new(raw_token)
|
227
|
+
|
228
|
+
# Access the payload easily (recursive-open-struct)
|
229
|
+
token.payload.test
|
230
|
+
# => true
|
231
|
+
|
232
|
+
# Validate the token (we assume you configured the verification key, an/or
|
233
|
+
# you own custom JWT verification options here)
|
234
|
+
token.valid?
|
235
|
+
# => true
|
236
|
+
```
|
237
|
+
|
238
|
+
The following examples show you how to configure the
|
239
|
+
`Grape::Jwt::Authentication::Jwt` class the global way. This is useful for a
|
240
|
+
shared initializer place.
|
241
|
+
|
242
|
+
##### Issuer verification
|
243
|
+
|
244
|
+
The JSON Web Token issuer which should be used for verification. When `nil` we
|
245
|
+
also turn off the verification by default. (See the default JWT options)
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
Grape::Jwt::Authentication.configure do |conf|
|
249
|
+
conf.jwt_issuer = 'your-identity-provider'
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
##### Beholder (audience) verification
|
254
|
+
|
255
|
+
The resource server (namely the one which configures this right now)
|
256
|
+
which MUST be present on the JSON Web Token audience claim. When `nil` we
|
257
|
+
also turn off the verification by default. (See the default JWT options)
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
Grape::Jwt::Authentication.configure do |conf|
|
261
|
+
conf.jwt_beholder = 'your-resource-server'
|
262
|
+
end
|
263
|
+
```
|
264
|
+
|
265
|
+
##### Custom JWT verification options
|
266
|
+
|
267
|
+
You can configure a different JSON Web Token verification option hash if your
|
268
|
+
algorithm differs or you want some extra/different options. Just watch out
|
269
|
+
that you have to pass a proc to this configuration property. On the
|
270
|
+
`Grape::Jwt::Authentication::Jwt` class it has to be a simple hash. The default
|
271
|
+
is here the `RS256` algorithm with enabled expiration check, and issuer+audience
|
272
|
+
check when the `jwt_issuer` / `jwt_beholder` are configured accordingly.
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
Grape::Jwt::Authentication.configure do |conf|
|
276
|
+
conf.jwt_options = proc do
|
277
|
+
# See: https://github.com/jwt/ruby-jwt
|
278
|
+
{ algorithm: 'HS256' }
|
279
|
+
end
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
283
|
+
##### Custom JWT verification key
|
284
|
+
|
285
|
+
You can configure your own verification key on the `Jwt` wrapper class. This
|
286
|
+
way you can pass your HMAC secret or your ECDSA public key to the JSON Web
|
287
|
+
Token validation method. Here you need to pass a proc, on the
|
288
|
+
`Grape::Jwt::Authentication::Jwt` class it has to be a scalar value. By default
|
289
|
+
we use the `RsaPublicKey` class to retrieve the RSA public key.
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
Grape::Jwt::Authentication.configure do |conf|
|
293
|
+
conf.jwt_verification_key = proc do
|
294
|
+
# Retrieve your verification key (RSA, ECDSA, HMAC secret)
|
295
|
+
# the way you like, and pass it back here.
|
296
|
+
end
|
297
|
+
end
|
298
|
+
```
|
299
|
+
|
300
|
+
### Per-API configuration
|
301
|
+
|
302
|
+
Imagine the migration of your API (say v2) and also the JSON Web Token payload
|
303
|
+
changes in a way you need to handle. Maybe you want to be more strict on
|
304
|
+
version 2 than on your old version 1. For this you can make use of the local
|
305
|
+
configuration of the JWT authenticator, on your specific Grape API declaration.
|
306
|
+
Here comes an example usage:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
module UserApi
|
310
|
+
class ApiV2 < Grape::API
|
311
|
+
v2_auth_malformed = proc { |raw_token, app| [400, {}, ['Malformed!']] }
|
312
|
+
v2_auth_failed = proc { |token, app| [401, {}, ['Go away!']] }
|
313
|
+
|
314
|
+
# Enable JWT authentication on this API
|
315
|
+
include Grape::Jwt::Authentication
|
316
|
+
auth(:jwt, malformed: v2_auth_malformed,
|
317
|
+
failed: v2_auth_failed) do |token|
|
318
|
+
# Your new stricter v2 authenticator.
|
319
|
+
false
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
325
|
+
### Full RSA256 example
|
326
|
+
|
327
|
+
Here comes a full example of the opinionated `RSA256` algorithm usage with a
|
328
|
+
remote RSA public key location, enabled caching and a full token payload
|
329
|
+
verification.
|
330
|
+
|
331
|
+
```ruby
|
332
|
+
# On an initializer ..
|
333
|
+
Grape::Jwt::Authentication.configure do |conf|
|
334
|
+
# The remote RSA public key location and enabled caching to limit the
|
335
|
+
# traffic on the remote server.
|
336
|
+
conf.rsa_public_key_url = 'https://your.identity.provider/rsa_public_key'
|
337
|
+
conf.rsa_public_key_caching = true
|
338
|
+
conf.rsa_public_key_expiration = 10.minutes
|
339
|
+
|
340
|
+
# Configure the JWT wrapper.
|
341
|
+
conf.jwt_issuer = 'The Identity Provider'
|
342
|
+
conf.jwt_beholder = 'example-api'
|
343
|
+
|
344
|
+
# Let Grape handle the malformed error with correct response formatting.
|
345
|
+
# (XML, JSON)
|
346
|
+
conf.malformed_auth_handler = proc do |raw_token, app|
|
347
|
+
raise ArgumentError, 'Authorization header is malformed.'
|
348
|
+
end
|
349
|
+
|
350
|
+
# The same procedure for failed verifications. (XML, JSON formatting handled
|
351
|
+
# external by Grape)
|
352
|
+
conf.failed_auth_handler = proc do |token, app|
|
353
|
+
raise ArgumentError, 'Access denied.'
|
354
|
+
end
|
355
|
+
|
356
|
+
# Custom verification logic.
|
357
|
+
conf.authenticator = proc do |token|
|
358
|
+
# Parse and instantiate a JWT verification instance
|
359
|
+
jwt = Grape::Jwt::Authentication::Jwt.new(token)
|
360
|
+
|
361
|
+
# We just allow valid access tokens
|
362
|
+
jwt.access_token? && jwt.valid?
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
# On your Grape API ..
|
367
|
+
module UserApi
|
368
|
+
class ApiV1 < Grape::API
|
369
|
+
# Enable JWT authentication on this API
|
370
|
+
include Grape::Jwt::Authentication
|
371
|
+
auth :jwt
|
372
|
+
end
|
373
|
+
end
|
374
|
+
```
|
375
|
+
|
376
|
+
## Development
|
377
|
+
|
378
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
379
|
+
`rake spec` to run the tests. You can also run `bin/console` for an interactive
|
380
|
+
prompt that will allow you to experiment.
|
381
|
+
|
382
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
383
|
+
release a new version, update the version number in `version.rb`, and then run
|
384
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
385
|
+
git commits and tags, and push the `.gem` file to
|
386
|
+
[rubygems.org](https://rubygems.org).
|
387
|
+
|
388
|
+
## Contributing
|
389
|
+
|
390
|
+
Bug reports and pull requests are welcome on GitHub at
|
391
|
+
https://github.com/hausgold/grape-jwt-authentication.
|