warden-auth0 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +17 -0
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +51 -0
- data/.travis.yml +21 -0
- data/CHANGELOG.md +97 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Dockerfile +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +242 -0
- data/Rakefile +8 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +12 -0
- data/issue_template.md +25 -0
- data/lib/warden/auth0/env_helper.rb +62 -0
- data/lib/warden/auth0/errors.rb +38 -0
- data/lib/warden/auth0/header_parser.rb +47 -0
- data/lib/warden/auth0/strategy.rb +88 -0
- data/lib/warden/auth0/token_decoder.rb +33 -0
- data/lib/warden/auth0/version.rb +7 -0
- data/lib/warden/auth0.rb +68 -0
- data/warden-auth0.gemspec +40 -0
- metadata +263 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6535f50d8f192c86cebdd135e411c1e7d28f54c2681a4a3993b730dfaed368b5
|
4
|
+
data.tar.gz: 0df77297cee513a2eb030e6456f5c4b38b7a3780c8e34682e5dea388f7c50303
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4438b8d430ce357ce55bf6b9088ba27a38e00f7d9232e615fd71cda465e77aef224bea62679211edbf4f0bb99d3ab4ea354be9bf5c1ce46798dbfbbee18bbe60
|
7
|
+
data.tar.gz: 9c2b3dcb75741bab6732faf2d5876b2d07b8e42978f4baa7e5e478ecc23f019f8e78dce919d4d04b5a09e2b82364710dd188a0960c6eb6e8abaa285730efd017
|
data/.codeclimate.yml
ADDED
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
github: waiting-for-dev
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require: rubocop-rspec
|
2
|
+
AllCops:
|
3
|
+
TargetRubyVersion: 2.7
|
4
|
+
Exclude:
|
5
|
+
- Gemfile
|
6
|
+
- warden-jwt_auth.gemspec
|
7
|
+
- spec/support/shared_contexts/*rb
|
8
|
+
- vendor/**/*
|
9
|
+
RSpec/NestedGroups:
|
10
|
+
Max: 3
|
11
|
+
RSpec/MessageExpectation:
|
12
|
+
EnforcedStyle: 'expect'
|
13
|
+
Metrics/BlockLength:
|
14
|
+
Exclude:
|
15
|
+
- "spec/**/*.rb"
|
16
|
+
Style/SafeNavigation:
|
17
|
+
Enabled: false
|
18
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
19
|
+
Enabled: true
|
20
|
+
Layout/SpaceAroundMethodCallOperator:
|
21
|
+
Enabled: true
|
22
|
+
Lint/DeprecatedOpenSSLConstant:
|
23
|
+
Enabled: true
|
24
|
+
Lint/MixedRegexpCaptureTypes:
|
25
|
+
Enabled: true
|
26
|
+
Lint/RaiseException:
|
27
|
+
Enabled: true
|
28
|
+
Lint/StructNewOverride:
|
29
|
+
Enabled: true
|
30
|
+
Style/AccessorGrouping:
|
31
|
+
Enabled: true
|
32
|
+
Style/BisectedAttrAccessor:
|
33
|
+
Enabled: true
|
34
|
+
Style/ExponentialNotation:
|
35
|
+
Enabled: true
|
36
|
+
Style/HashEachMethods:
|
37
|
+
Enabled: true
|
38
|
+
Style/HashTransformKeys:
|
39
|
+
Enabled: true
|
40
|
+
Style/HashTransformValues:
|
41
|
+
Enabled: true
|
42
|
+
Style/RedundantAssignment:
|
43
|
+
Enabled: true
|
44
|
+
Style/RedundantFetchBlock:
|
45
|
+
Enabled: true
|
46
|
+
Style/RedundantRegexpCharacterClass:
|
47
|
+
Enabled: true
|
48
|
+
Style/RedundantRegexpEscape:
|
49
|
+
Enabled: true
|
50
|
+
Style/SlicingWithRange:
|
51
|
+
Enabled: true
|
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
rvm:
|
4
|
+
- 2.6
|
5
|
+
- 2.7
|
6
|
+
- 3.0
|
7
|
+
- ruby-head
|
8
|
+
before_install:
|
9
|
+
- gem update --system --no-doc
|
10
|
+
- gem install bundler
|
11
|
+
script:
|
12
|
+
- bundle exec rspec
|
13
|
+
- bundle exec rubocop
|
14
|
+
- bundle exec codeclimate-test-reporter
|
15
|
+
jobs:
|
16
|
+
allow_failures:
|
17
|
+
- rvm: ruby-head
|
18
|
+
addons:
|
19
|
+
code_climate:
|
20
|
+
repo_token:
|
21
|
+
secure: neJ5LVLV6vgeCnerSQjUpLuQDvxEH87iW8swCSWl2hTtPcD/GuwYSeSXnhH72HVHi/9basHHhaYPcE2YeBwBCr39PhiHMNwS5GGGk/RGjKpU/Gt1KXV8KXTbNGT4v+ZMM3cdsdDfe8OnzGguNVsdxseHa3KE2pyuvo2a0swXwKa7BU9VB/3ZoZvvfI3Xr9im4eklWam5yCwVR0FOF7epzmNTKMXcUga2BOc9PV5aVELzLILLCHCJSCupe5Rx8mfcsRoRmZXKduF8Ke3eq8eULvLEo4EGfC107najOqrKt7x8uDVIsuGrP4LUQ4ainmNEb2jIvpjuqAxpusMjhpjCINF1Tn0OXK93OXAp4QKeIYoYEqKtzRxX0TWFNWHB8ombF9HTMF2DmloDZyFRiI40JSMImU0hc4MDxRgiTW5MDWGbohDaJ+9VV6+rIqtlEfLhgj1grFBAroaJce9BB7RQEmfsZPzhC2VXwGxHw/YkJgzBNGq1/9E1DoTY9RPSNTQfSRodhI3XW8LSQSHTBeXZvymVcjeOyYgjzJYviLHR8QS4cXpUALtlFXyaMkPHUBLUn8XsBa5Azfh5y3qPMGiJq1/qaHA4mKj5ls+ngFbzOq82sYGAKgQHj/ZDb+FZMQQanp4jyWADKcpXcmINb9jEQwkU0bjpuhUYtghASxH1Kl8=
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
|
+
|
7
|
+
## [0.8.0] - 2024-06-28
|
8
|
+
- Add support for issue claim ([56](https://github.com/waiting-for-dev/warden-jwt_auth/pull/56))
|
9
|
+
|
10
|
+
## [0.8.0] - 2023-01-31
|
11
|
+
- Add support for secret rotation ([49](https://github.com/waiting-for-dev/warden-jwt_auth/pull/49))
|
12
|
+
- Support dry-* v1 ([52](https://github.com/waiting-for-dev/warden-jwt_auth/pull/52))
|
13
|
+
|
14
|
+
## [0.7.0] - 2022-09-12
|
15
|
+
- Support asymmetric algorithms ([40](https://github.com/waiting-for-dev/warden-jwt_auth/issues/40))
|
16
|
+
|
17
|
+
## [0.6.0] - 2021-09-21
|
18
|
+
- Support ruby 3.0 and deprecate 2.5
|
19
|
+
- Fixed dry-configurable compatibility. ([28](https://github.com/waiting-for-dev/warden-jwt_auth/issues/28))
|
20
|
+
|
21
|
+
## [0.5.0]
|
22
|
+
### Fixed
|
23
|
+
- Fixed dry-configurable compatibility. ([28](https://github.com/waiting-for-dev/warden-jwt_auth/issues/28))
|
24
|
+
|
25
|
+
## [0.4.2] - 2020-03-19
|
26
|
+
### Fixed
|
27
|
+
- Lock dry-configurable dependency to fix upstream regression. ([21](https://github.com/waiting-for-dev/warden-jwt_auth/issues/21))
|
28
|
+
- Fix ruby 2.7 warnings (@trevorrjohn [23](https://github.com/waiting-for-dev/warden-jwt_auth/pull/23) )
|
29
|
+
|
30
|
+
## [0.4.1] - 2020-02-23
|
31
|
+
### Fixed
|
32
|
+
- Upgrade dry-configurable dependency to fix upstream bug preventing
|
33
|
+
warden-jwt_auth to be loaded ([21](https://github.com/waiting-for-dev/warden-jwt_auth/issues/21)).
|
34
|
+
|
35
|
+
## [0.4.0] - 2019-08-01
|
36
|
+
### Added
|
37
|
+
- Allow configuration of the signing algorithm ([19](https://github.com/waiting-for-dev/warden-jwt_auth/pull/19)].
|
38
|
+
|
39
|
+
## [0.3.6] - 2019-03-29
|
40
|
+
### Fixed
|
41
|
+
- Update depencies.
|
42
|
+
|
43
|
+
## [0.3.5] - 2018-01-30
|
44
|
+
### Fixed
|
45
|
+
- Do not disallow fetching JWT scopes from session
|
46
|
+
|
47
|
+
## [0.3.4] - 2018-01-09
|
48
|
+
### Fixed
|
49
|
+
- Do not log out from session for standard AJAX requests
|
50
|
+
|
51
|
+
## [0.3.3] - 2017-12-31
|
52
|
+
### Fixed
|
53
|
+
- Check it is not a html request when disallowing fetching from session
|
54
|
+
|
55
|
+
## [0.3.2] - 2017-12-23
|
56
|
+
### Fixed
|
57
|
+
- Do not couple `aud_header` env value to the setting
|
58
|
+
|
59
|
+
## [0.3.1] - 2017-12-11
|
60
|
+
### Added
|
61
|
+
- Ensure JWT scopes are not fetched from session. Workaround for
|
62
|
+
https://github.com/hassox/warden/pull/118
|
63
|
+
|
64
|
+
## [0.3.0] - 2017-12-06
|
65
|
+
### Added
|
66
|
+
- Add and call hook method `on_jwt_dispatch` on user instance
|
67
|
+
- Encode and validate an `aud` claim from the request headers
|
68
|
+
|
69
|
+
## [0.2.1] - 2017-12-04
|
70
|
+
### Added
|
71
|
+
- Allow configuring classes as strings
|
72
|
+
|
73
|
+
### Fixed
|
74
|
+
- Take `PATH_INFO` as an empty string when it is not present
|
75
|
+
|
76
|
+
## [0.2.0] - 2017-11-23
|
77
|
+
### Added
|
78
|
+
- `fail!` with message
|
79
|
+
|
80
|
+
### Fixed
|
81
|
+
- Unauthorize when fetched user is nil
|
82
|
+
|
83
|
+
## [0.1.4] - 2017-11-21
|
84
|
+
### Fixed
|
85
|
+
- Update `jwt` dependency
|
86
|
+
|
87
|
+
## [0.1.3] - 2017-04-15
|
88
|
+
### Fixed
|
89
|
+
- Coerce `sub` to string to conform with JWT specification
|
90
|
+
|
91
|
+
## [0.1.2] - 2017-04-13
|
92
|
+
### Fixed
|
93
|
+
- Ignore expired tokens on revocation instead of fail
|
94
|
+
|
95
|
+
## [0.1.1] - 2017-02-28
|
96
|
+
### Fixed
|
97
|
+
- Explicit require of `securerandom` standard library
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at marc@lamarciana.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Dockerfile
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Marc Busqué
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
# Warden::Auth0
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/warden-jwt_auth.svg)](https://badge.fury.io/rb/warden-jwt_auth)
|
4
|
+
[![Build Status](https://travis-ci.org/waiting-for-dev/warden-jwt_auth.svg?branch=master)](https://travis-ci.org/waiting-for-dev/warden-jwt_auth)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/waiting-for-dev/warden-jwt_auth/badges/gpa.svg)](https://codeclimate.com/github/waiting-for-dev/warden-jwt_auth)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/waiting-for-dev/warden-jwt_auth/badges/coverage.svg)](https://codeclimate.com/github/waiting-for-dev/warden-jwt_auth/coverage)
|
7
|
+
|
8
|
+
`warden-jwt_auth` is a [warden](https://github.com/hassox/warden) extension which uses [JWT](https://jwt.io/) tokens for user authentication. It follows [secure by default](https://en.wikipedia.org/wiki/Secure_by_default) principle.
|
9
|
+
|
10
|
+
This gem is just a replacement for cookies when these can't be used. As
|
11
|
+
cookies, a token expired with `warden-jwt_auth` will mandatorily have an
|
12
|
+
expiration time. If you need that your users never sign out, you will be better
|
13
|
+
off with a solution using refresh tokens, like some implementation of OAuth2.
|
14
|
+
|
15
|
+
You can read about which security concerns this library takes into account and about JWT generic secure usage in the following series of posts:
|
16
|
+
|
17
|
+
- [Stand Up for JWT Revocation](http://waiting-for-dev.github.io/blog/2017/01/23/stand_up_for_jwt_revocation)
|
18
|
+
- [JWT Revocation Strategies](http://waiting-for-dev.github.io/blog/2017/01/24/jwt_revocation_strategies)
|
19
|
+
- [JWT Secure Usage](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage)
|
20
|
+
- [A secure JWT authentication implementation for Rack and Rails](http://waiting-for-dev.github.io/blog/2017/01/26/a_secure_jwt_authentication_implementation_for_rack_and_rails)
|
21
|
+
|
22
|
+
If what you need is a JWT authentication library for [devise](https://github.com/plataformatec/devise), better look at [devise-jwt](https://github.com/waiting-for-dev/devise-jwt), which is just a thin layer on top of this gem.
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
gem 'warden-jwt_auth'
|
28
|
+
```
|
29
|
+
|
30
|
+
And then execute:
|
31
|
+
|
32
|
+
$ bundle
|
33
|
+
|
34
|
+
Or install it yourself as:
|
35
|
+
|
36
|
+
$ gem install warden-jwt_auth
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
You can look at this gem's wiki to see some [example applications](https://github.com/waiting-for-dev/warden-jwt_auth/wiki). Please, add yours if you think it can help somebody.
|
41
|
+
|
42
|
+
At its core, this library consists of:
|
43
|
+
|
44
|
+
- A Warden strategy that authenticates a user if a valid JWT token is present in the request headers.
|
45
|
+
- A rack middleware which adds a JWT token to the response headers in configured requests.
|
46
|
+
- A rack middleware which revokes JWT tokens in configured requests.
|
47
|
+
|
48
|
+
As you see, JWT revocation is supported. I wrote [why I think JWT tokens revocation is useful and needed](http://waiting-for-dev.github.io/blog/2017/01/23/stand_up_for_jwt_revocation/).
|
49
|
+
|
50
|
+
### Secret key configuration
|
51
|
+
|
52
|
+
First of all, you have to configure the secret key that will be used to sign generated tokens.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
Warden::Auth0.configure do |config|
|
56
|
+
config.secret = ENV['WARDEN_JWT_SECRET_KEY']
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
**Important:** You are encouraged to use a dedicated secret key, different than others in use in your application. If several components share the same secret key, chances that a vulnerability in one of them has a wider impact increase. Also, never share your secrets pushing it to a remote repository, you are better off using an environment variable like in the example.
|
61
|
+
|
62
|
+
Currently, HS256 algorithm is the default.
|
63
|
+
Configure the matching secret and algorithm name to use a different one (e.g. RS256) (see [ruby-jwt](https://github.com/jwt/ruby-jwt#algorithms-and-usage) to see which are supported)
|
64
|
+
```ruby
|
65
|
+
Warden::Auth0.configure do |config|
|
66
|
+
config.secret = OpenSSL::PKey::RSA.new(ENV['WARDEN_JWT_SECRET_KEY'])
|
67
|
+
config.algorithm = ENV['WARDEN_JWT_ALGORITHM']
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
If the algorithm is asymmetric (e.g. RS256) and necessitates a different decoding secret than the encoding secret, configure the `decoding_secret` setting as well.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
Warden::Auth0.configure do |config|
|
75
|
+
config.secret = OpenSSL::PKey::RSA.new(ENV['WARDEN_JWT_PRIVATE_KEY'])
|
76
|
+
config.decoding_secret = OpenSSL::PKey::RSA.new(ENV['WARDEN_JWT_PUBLIC_KEY'])
|
77
|
+
config.algorithm = 'RS256' # or other asymmetric algorithm
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
### Warden scopes configuration
|
82
|
+
|
83
|
+
You have to map the warden scopes that will be authenticatable through JWT, with the user repositories from where these scope user records can be fetched. If a string is supplied, the user repository will first be looked up as a constant.
|
84
|
+
|
85
|
+
For instance:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
config.mappings = { user: UserRepository }
|
89
|
+
```
|
90
|
+
|
91
|
+
For this example, `UserRepository` must implement a method `find_for_jwt_authentication` that takes as argument the `sub` claim in the JWT payload. This method should return a user record from `:user` scope:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
module UserRepository
|
95
|
+
# @returns User
|
96
|
+
def self.find_for_jwt_authentication(sub)
|
97
|
+
Repo.find_user_by_id(sub)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
User records must implement a `jwt_subject` method returning what should be encoded in the `sub` claim on dispatch time. Be aware that what is returned must be coercible to string in order to conform with [RFC7519 standard for `sub` claim](https://tools.ietf.org/html/rfc7519#section-4.1.2).
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
User = Struct.new(:id, :name)
|
106
|
+
def jwt_subject
|
107
|
+
id
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
User records may also implement a `jwt_payload` method, which gives it a chance to add something to the JWT payload:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
def jwt_payload
|
116
|
+
{ 'foo' => 'bar' }
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
Just when a token is going to be dispatched to a client, a hook method `on_jwt_dispatch` is invoked, only when it exist, on the user record. This method takes the `token` and the `payload` as arguments.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
def on_jwt_dispatch(token, payload)
|
124
|
+
# Do something
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
### Middlewares addition
|
129
|
+
|
130
|
+
You need to add `Warden::Auth0::Middleware` to your rack middlewares stack. Actually, it is just a wrapper which adds two middlewares that do the actual job: dispatching tokens and revoking tokens.
|
131
|
+
|
132
|
+
### Token dispatch configuration
|
133
|
+
|
134
|
+
You need to tell which requests will dispatch tokens for the user that has been previously authenticated (usually through some other warden strategy, such as one requiring username and email parameters).
|
135
|
+
|
136
|
+
To configure it, you must provide a bidimensional array, each item being an array of two elements: the request method and a regular expression that must match the request path.
|
137
|
+
|
138
|
+
For example:
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
config.dispatch_requests = [
|
142
|
+
['POST', %r{^/sign_in$}]
|
143
|
+
]
|
144
|
+
```
|
145
|
+
|
146
|
+
**Important**: You are encouraged to delimit your regular expression with `^` and `$` to avoid unintentional matches.
|
147
|
+
|
148
|
+
Tokens will be returned in the `Authorization` response header (configurable via `config.token_header`), with format `Bearer #{token}`.
|
149
|
+
|
150
|
+
### Requests authentication
|
151
|
+
|
152
|
+
Once you have a valid token, you can authenticate following requests providing the token in the `Authorization` request header, with format `Bearer #{token}`.
|
153
|
+
|
154
|
+
### Revocation configuration
|
155
|
+
|
156
|
+
You need to tell which requests will revoke incoming JWT tokens.
|
157
|
+
|
158
|
+
To configure it, you must provide a bidimensional array, each item being an array of two elements: the request method and a regular expression that must match the request path.
|
159
|
+
|
160
|
+
For example:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
config.revocation_requests = [
|
164
|
+
['DELETE', %r{^/sign_out$}]
|
165
|
+
]
|
166
|
+
```
|
167
|
+
|
168
|
+
**Important**: You are encouraged to delimit your regular expression with `^` and `$` to avoid unintentional matches.
|
169
|
+
|
170
|
+
Besides, you need to configure which revocation strategy will be used for each scope. If a string is supplied, the revocation strategy will first be looked up as a constant.
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
config.revocation_strategies = { user: RevocationStrategy }
|
174
|
+
```
|
175
|
+
|
176
|
+
The implementation of the revocation strategy is also on your side. They just need to implement two methods: `jwt_revoked?` and `revoke_jwt`, both of them accepting as parameters the JWT payload and the user record, in this order.
|
177
|
+
|
178
|
+
You can read about which [JWT recovation strategies](http://waiting-for-dev.github.io/blog/2017/01/24/jwt_revocation_strategies/) can be implement with their pros and cons.
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
module RevocationStrategy
|
182
|
+
def self.jwt_revoked?(payload, user)
|
183
|
+
# Does something to check whether the JWT token is revoked for given user
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.revoke_jwt(payload, user)
|
187
|
+
# Does something to revoke the JWT token for given user
|
188
|
+
end
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
192
|
+
### Requesting client validation
|
193
|
+
|
194
|
+
Authentication will be refused if a client requesting to be authenticated through a token is not the same to which it was originally issued. To do so, the content of the header `JWT_AUD` (configurable via `config.aud_header`) is stored as `aud` claim. If you don't want to differentiate between clients, you don't need to provide that header.
|
195
|
+
|
196
|
+
**Important:** Be aware that this workflow is not bullet proof. In some scenarios a user can handcraft the request headers, therefore being able to impersonate any client. In such cases you could need something more robust, like an OAuth workflow with client id and client secret.
|
197
|
+
|
198
|
+
### Secret rotation
|
199
|
+
|
200
|
+
Secret rotation is supported by setting `rotation_secret`. Set the new secret as the `secret` and copy the previous secret to `rotation_secret`
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
Warden::Auth0.configure do |config|
|
204
|
+
config.secret = ENV['WARDEN_JWT_SECRET_KEY']
|
205
|
+
config.rotation_secret = ENV['WARDEN_JWT_SECRET_KEY_ROTATION']
|
206
|
+
end
|
207
|
+
```
|
208
|
+
|
209
|
+
You can remove the `rotation_secret` when you are condifent that large enough user base has the fetched the token encrypted with the new secret.
|
210
|
+
|
211
|
+
### Multiple issuers
|
212
|
+
|
213
|
+
When your application handles JWT tokens from multiple sources (e.g. webhooks authenticated via provider JTW tokens) you can configure this gem to use the [issuer claim](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1) to only handle tokens it has issued.
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
Warden::Auth0.configure do |config|
|
217
|
+
config.secret = ENV['WARDEN_JWT_SECRET_KEY']
|
218
|
+
config.issuer = 'http://my-application.com'
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
## Development
|
223
|
+
|
224
|
+
There are docker and docker-compose files configured to create a development environment for this gem. So, if you use Docker you only need to run:
|
225
|
+
|
226
|
+
`docker-compose up -d`
|
227
|
+
|
228
|
+
An then, for example:
|
229
|
+
|
230
|
+
`docker-compose exec app rspec`
|
231
|
+
|
232
|
+
## Contributing
|
233
|
+
|
234
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/waiting-for-dev/warden-jwt_auth. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
235
|
+
|
236
|
+
## Release Policy
|
237
|
+
|
238
|
+
`warden-jwt_auth` follows the principles of [semantic versioning](http://semver.org/).
|
239
|
+
|
240
|
+
## License
|
241
|
+
|
242
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !/usr/bin/env ruby
|
4
|
+
|
5
|
+
require 'bundler/setup'
|
6
|
+
require 'warden/jwt_auth'
|
7
|
+
|
8
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
9
|
+
# with your gem easier. You can also use a different console, if you like.
|
10
|
+
|
11
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
12
|
+
# require "pry"
|
13
|
+
# Pry.start
|
14
|
+
|
15
|
+
require 'irb'
|
16
|
+
IRB.start
|
data/bin/setup
ADDED
data/docker-compose.yml
ADDED
data/issue_template.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Please, for a bug report fill in the following template. Before that, make sure to read the whole [README](https://github.com/waiting-for-dev/warden-jwt_auth/blob/master/README.md).
|
2
|
+
|
3
|
+
Feature requests and questions about `warden-jwt_auth` are also accepted.
|
4
|
+
|
5
|
+
## Expected behavior
|
6
|
+
|
7
|
+
## Actual behavior
|
8
|
+
|
9
|
+
## Steps to Reproduce the Problem
|
10
|
+
|
11
|
+
1.
|
12
|
+
2.
|
13
|
+
3.
|
14
|
+
|
15
|
+
## Debugging information
|
16
|
+
|
17
|
+
Provide following information. Please, format pasted output as code. Feel free to remove the secret key value.
|
18
|
+
|
19
|
+
- Version of `warden-jwt_auth` in use
|
20
|
+
- Output of `Warden::Auth0.config`
|
21
|
+
- If your issue is related with not getting a JWT from the server:
|
22
|
+
- Involved request path, method and request headers
|
23
|
+
- Response headers for that request
|
24
|
+
- If your issue is related with not being able to revoke a JWT:
|
25
|
+
- Involved request path, method and request headers
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module Auth0
|
5
|
+
# Helper functions to centralize working with rack env.
|
6
|
+
#
|
7
|
+
# It follows
|
8
|
+
# [rack](http://www.rubydoc.info/github/rack/rack/file/SPEC#The_Environment)
|
9
|
+
# and [PEP 333](https://www.python.org/dev/peps/pep-0333/#environ-variables)
|
10
|
+
# conventions.
|
11
|
+
module EnvHelper
|
12
|
+
# Returns PATH_INFO environment variable
|
13
|
+
#
|
14
|
+
# @param env [Hash] Rack env
|
15
|
+
# @return [String]
|
16
|
+
def self.path_info(env)
|
17
|
+
env['PATH_INFO'] || ''
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns REQUEST_METHOD environment variable
|
21
|
+
#
|
22
|
+
# @param env [Hash] Rack env
|
23
|
+
# @return [String]
|
24
|
+
def self.request_method(env)
|
25
|
+
env['REQUEST_METHOD']
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns header configured through `token_header` option
|
29
|
+
#
|
30
|
+
# @param env [Hash] Rack env
|
31
|
+
# @return [String]
|
32
|
+
def self.authorization_header(env)
|
33
|
+
header_env_name = env_name(Auth0.config.token_header)
|
34
|
+
env[header_env_name]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns a copy of `env` with value added to the environment variable
|
38
|
+
# configured through `token_header` option
|
39
|
+
#
|
40
|
+
# Be aware than `env` is not modified in place and still an updated copy
|
41
|
+
# is returned.
|
42
|
+
#
|
43
|
+
# @param env [Hash] Rack env
|
44
|
+
# @param value [String]
|
45
|
+
# @return [Hash] modified rack env
|
46
|
+
def self.set_authorization_header(env, value)
|
47
|
+
env = env.dup
|
48
|
+
header_env_name = env_name(Auth0.config.token_header)
|
49
|
+
env[header_env_name] = value
|
50
|
+
env
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the ENV name for a given header
|
54
|
+
#
|
55
|
+
# @param header [String] Header name
|
56
|
+
# @return [String]
|
57
|
+
def self.env_name(header)
|
58
|
+
('HTTP_' + header.upcase).tr('-', '_')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module Auth0
|
5
|
+
module Errors
|
6
|
+
# Error raised when trying to decode a token that has been revoked for an
|
7
|
+
# user
|
8
|
+
class RevokedToken < JWT::DecodeError
|
9
|
+
end
|
10
|
+
|
11
|
+
# Error raised when no issuer has been configured
|
12
|
+
class NoConfiguredIssuer < JWT::DecodeError
|
13
|
+
end
|
14
|
+
|
15
|
+
# Error raised when no aud has been configured
|
16
|
+
class NoConfiguredAud < JWT::DecodeError
|
17
|
+
end
|
18
|
+
|
19
|
+
# Error raised when the user decoded from a token is nil
|
20
|
+
class NilUser < JWT::DecodeError
|
21
|
+
end
|
22
|
+
|
23
|
+
# Error raised when trying to decode a token whose "issuer" does not match the expected one
|
24
|
+
class WrongIssuer < JWT::DecodeError
|
25
|
+
end
|
26
|
+
|
27
|
+
# Error raised when trying to decode a token for an scope that doesn't
|
28
|
+
# match the one encoded in the payload
|
29
|
+
class WrongScope < JWT::DecodeError
|
30
|
+
end
|
31
|
+
|
32
|
+
# Error raised when trying to decode a token which `aud` claim does not
|
33
|
+
# match with the expected one
|
34
|
+
class WrongAud < JWT::DecodeError
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module Auth0
|
5
|
+
# Helpers to parse token from a request and to a response
|
6
|
+
module HeaderParser
|
7
|
+
# Method for `Authorization` header. Token is present in request/response
|
8
|
+
# headers as `Bearer %token%`
|
9
|
+
METHOD = 'Bearer'
|
10
|
+
|
11
|
+
# Parses the token from a rack request
|
12
|
+
#
|
13
|
+
# @param env [Hash] rack env hash
|
14
|
+
# @return [String] JWT token
|
15
|
+
# @return [nil] if token is not present
|
16
|
+
def self.from_env(env)
|
17
|
+
auth = EnvHelper.authorization_header(env)
|
18
|
+
return nil unless auth
|
19
|
+
|
20
|
+
method, token = auth.split
|
21
|
+
method == METHOD ? token : nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a copy of `env` with token added to the header configured through
|
25
|
+
# `token_header` option. Be aware than `env` is not modified in place.
|
26
|
+
#
|
27
|
+
# @param env [Hash] rack env hash
|
28
|
+
# @param token [String] JWT token
|
29
|
+
# @return [Hash] modified rack env
|
30
|
+
def self.to_env(env, token)
|
31
|
+
EnvHelper.set_authorization_header(env, "#{METHOD} #{token}")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns a copy of headers with token added in the `Authorization` key.
|
35
|
+
# Be aware that headers is not modified in place
|
36
|
+
#
|
37
|
+
# @param headers [Hash] rack hash response headers
|
38
|
+
# @param token [String] JWT token
|
39
|
+
# @return [Hash] response headers with the token added
|
40
|
+
def self.to_headers(headers, token)
|
41
|
+
headers = headers.dup
|
42
|
+
headers[Auth0.config.token_header] = "#{METHOD} #{token}"
|
43
|
+
headers
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'warden'
|
4
|
+
|
5
|
+
module Warden
|
6
|
+
module Auth0
|
7
|
+
# Warden strategy to authenticate a user through a JWT token in the
|
8
|
+
# `Authorization` request header
|
9
|
+
class Strategy < Warden::Strategies::Base
|
10
|
+
def valid?
|
11
|
+
token_exists? && issuer_claim_valid? && aud_claim_valid?
|
12
|
+
end
|
13
|
+
|
14
|
+
def store?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate!
|
19
|
+
raise Errors::WrongIssuer, 'wrong issuer' unless issuer_claim_valid?
|
20
|
+
|
21
|
+
raise Errors::WrongAud, 'wrong audience' unless aud_claim_valid?
|
22
|
+
|
23
|
+
user = Warden::Auth0.config.user_resolver.call(decoded_token)
|
24
|
+
|
25
|
+
raise Warden::Auth0::Errors::NilUser, 'nil user' unless user
|
26
|
+
|
27
|
+
success!(user)
|
28
|
+
rescue JWT::DecodeError => e
|
29
|
+
puts "Failing to authenticate with #{e.message}"
|
30
|
+
fail!(e.message)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def issuer_claim_valid?
|
36
|
+
issuer = configured_issuer
|
37
|
+
issuer_matches?(decoded_token, issuer)
|
38
|
+
rescue JWT::DecodeError
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def aud_claim_valid?
|
43
|
+
aud = configured_aud
|
44
|
+
aud_matches?(decoded_token, aud)
|
45
|
+
rescue JWT::DecodeError
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def decoded_token
|
50
|
+
TokenDecoder.new.call(token)
|
51
|
+
end
|
52
|
+
|
53
|
+
def configured_aud
|
54
|
+
configured_aud = Warden::Auth0.config.aud
|
55
|
+
raise Errors::NoConfiguredAud if configured_aud.nil?
|
56
|
+
|
57
|
+
configured_aud
|
58
|
+
end
|
59
|
+
|
60
|
+
def configured_issuer
|
61
|
+
configured_issuer = Warden::Auth0.config.issuer
|
62
|
+
raise Errors::NoConfiguredIssuer if configured_issuer.nil?
|
63
|
+
|
64
|
+
configured_issuer
|
65
|
+
end
|
66
|
+
|
67
|
+
def token_exists?
|
68
|
+
!token.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
def issuer_matches?(payload, issuer)
|
72
|
+
payload['iss'] == issuer.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def aud_matches?(payload, aud)
|
76
|
+
return true if payload['aud'] == aud.to_s
|
77
|
+
|
78
|
+
payload['aud'].is_a?(Array) && payload['aud'].include?(aud)
|
79
|
+
end
|
80
|
+
|
81
|
+
def token
|
82
|
+
@token ||= HeaderParser.from_env(env)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Warden::Strategies.add(:auth0, Warden::Auth0::Strategy)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt/error'
|
4
|
+
|
5
|
+
module Warden
|
6
|
+
module Auth0
|
7
|
+
# Decodes a JWT into a hash payload into a JWT token
|
8
|
+
class TokenDecoder
|
9
|
+
include Auth0::Import['decoding_secret', 'algorithm']
|
10
|
+
|
11
|
+
# Decodes the payload from a JWT as a hash
|
12
|
+
#
|
13
|
+
# @see JWT.decode for all the exceptions than can be raised when given
|
14
|
+
# token is invalid
|
15
|
+
#
|
16
|
+
# @param token [String] a JWT
|
17
|
+
# @return [Hash] payload decoded from the JWT
|
18
|
+
def call(token)
|
19
|
+
decode(token, decoding_secret)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def decode(token, secret)
|
25
|
+
JWT.decode(token,
|
26
|
+
secret,
|
27
|
+
true,
|
28
|
+
algorithm: algorithm,
|
29
|
+
verify_jti: true)[0]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/warden/auth0.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/configurable'
|
4
|
+
require 'dry/auto_inject'
|
5
|
+
require 'jwt'
|
6
|
+
require 'warden'
|
7
|
+
|
8
|
+
module Warden
|
9
|
+
# Auth0 authentication plugin for warden.
|
10
|
+
#
|
11
|
+
# It consists of a strategy which tries to authenticate an user decoding a
|
12
|
+
# token present in the `Authentication` header (as `Bearer %token%`).
|
13
|
+
module Auth0
|
14
|
+
extend Dry::Configurable
|
15
|
+
|
16
|
+
def symbolize_keys(hash)
|
17
|
+
hash.transform_keys(&:to_sym)
|
18
|
+
end
|
19
|
+
|
20
|
+
def upcase_first_items(array)
|
21
|
+
array.map do |tuple|
|
22
|
+
method, path = tuple
|
23
|
+
[method.to_s.upcase, path]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def constantize_values(hash)
|
28
|
+
hash.transform_values do |value|
|
29
|
+
value.is_a?(String) ? Object.const_get(value) : value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module_function :constantize_values, :symbolize_keys, :upcase_first_items
|
34
|
+
|
35
|
+
# The secret used to decode the token, defaults to `secret` if not provided
|
36
|
+
setting :decoding_secret, constructor: ->(value) { value || config.secret }
|
37
|
+
|
38
|
+
# Request header that will be used for receiving and returning the token.
|
39
|
+
setting :token_header, default: 'Authorization'
|
40
|
+
|
41
|
+
# The algorithm used to encode the token
|
42
|
+
setting :algorithm
|
43
|
+
|
44
|
+
# The issuer claims associated with the tokens
|
45
|
+
#
|
46
|
+
# Will be used to only apply the warden strategy when the issuer matches.
|
47
|
+
# This allows for multiple token issuers being used.
|
48
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
|
49
|
+
setting :issuer, default: nil
|
50
|
+
|
51
|
+
# The aud claims associated with the tokens
|
52
|
+
#
|
53
|
+
# Will be used to only apply the warden strategy when the audience matches.
|
54
|
+
setting :aud, default: nil
|
55
|
+
|
56
|
+
# This is a method that takes in the payload sub and should return a User
|
57
|
+
setting :user_resolver
|
58
|
+
|
59
|
+
Import = Dry::AutoInject(config)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
require 'warden/auth0/version'
|
64
|
+
require 'warden/auth0/errors'
|
65
|
+
require 'warden/auth0/header_parser'
|
66
|
+
require 'warden/auth0/env_helper'
|
67
|
+
require 'warden/auth0/token_decoder'
|
68
|
+
require 'warden/auth0/strategy'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'warden/auth0/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'warden-auth0'
|
9
|
+
spec.version = Warden::Auth0::VERSION
|
10
|
+
spec.authors = ['1KOMMA5º']
|
11
|
+
|
12
|
+
spec.summary = 'Auth0 authentication for Warden.'
|
13
|
+
spec.description = 'Auth0 authentication for Warden, ORM agnostic and accepting the implementation of token revocation strategies.'
|
14
|
+
spec.homepage = 'https://github.com/sarakola/warden-jwt_auth'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
23
|
+
|
24
|
+
spec.add_dependency 'dry-auto_inject', '>= 0.8', '< 2'
|
25
|
+
spec.add_dependency 'dry-configurable', '>= 0.13', '< 2'
|
26
|
+
spec.add_dependency 'jwt', '~> 2.1'
|
27
|
+
spec.add_dependency 'warden', '~> 1.2'
|
28
|
+
|
29
|
+
spec.add_development_dependency 'bundler'
|
30
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.7'
|
31
|
+
spec.add_development_dependency 'rack-test', '~> 1.1'
|
32
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
33
|
+
spec.add_development_dependency 'rspec', '~> 3.8'
|
34
|
+
# Cops
|
35
|
+
spec.add_development_dependency 'rubocop', '~> 0.87'
|
36
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.42'
|
37
|
+
# Test reporting
|
38
|
+
spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
|
39
|
+
spec.add_development_dependency 'simplecov', '0.17'
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: warden-auth0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- 1KOMMA5º
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-09-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry-auto_inject
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.8'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: dry-configurable
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.13'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.13'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '2'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: jwt
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.1'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '2.1'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: warden
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.2'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '1.2'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: bundler
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: pry-byebug
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '3.7'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '3.7'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: rack-test
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '1.1'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '1.1'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: rake
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '12.3'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '12.3'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: rspec
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '3.8'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - "~>"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '3.8'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: rubocop
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - "~>"
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0.87'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - "~>"
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0.87'
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: rubocop-rspec
|
167
|
+
requirement: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - "~>"
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '1.42'
|
172
|
+
type: :development
|
173
|
+
prerelease: false
|
174
|
+
version_requirements: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - "~>"
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '1.42'
|
179
|
+
- !ruby/object:Gem::Dependency
|
180
|
+
name: codeclimate-test-reporter
|
181
|
+
requirement: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - "~>"
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '1.0'
|
186
|
+
type: :development
|
187
|
+
prerelease: false
|
188
|
+
version_requirements: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - "~>"
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '1.0'
|
193
|
+
- !ruby/object:Gem::Dependency
|
194
|
+
name: simplecov
|
195
|
+
requirement: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - '='
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0.17'
|
200
|
+
type: :development
|
201
|
+
prerelease: false
|
202
|
+
version_requirements: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - '='
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0.17'
|
207
|
+
description: Auth0 authentication for Warden, ORM agnostic and accepting the implementation
|
208
|
+
of token revocation strategies.
|
209
|
+
email:
|
210
|
+
executables: []
|
211
|
+
extensions: []
|
212
|
+
extra_rdoc_files: []
|
213
|
+
files:
|
214
|
+
- ".codeclimate.yml"
|
215
|
+
- ".github/FUNDING.yml"
|
216
|
+
- ".gitignore"
|
217
|
+
- ".rspec"
|
218
|
+
- ".rubocop.yml"
|
219
|
+
- ".travis.yml"
|
220
|
+
- CHANGELOG.md
|
221
|
+
- CODE_OF_CONDUCT.md
|
222
|
+
- Dockerfile
|
223
|
+
- Gemfile
|
224
|
+
- LICENSE.txt
|
225
|
+
- README.md
|
226
|
+
- Rakefile
|
227
|
+
- bin/console
|
228
|
+
- bin/setup
|
229
|
+
- docker-compose.yml
|
230
|
+
- issue_template.md
|
231
|
+
- lib/warden/auth0.rb
|
232
|
+
- lib/warden/auth0/env_helper.rb
|
233
|
+
- lib/warden/auth0/errors.rb
|
234
|
+
- lib/warden/auth0/header_parser.rb
|
235
|
+
- lib/warden/auth0/strategy.rb
|
236
|
+
- lib/warden/auth0/token_decoder.rb
|
237
|
+
- lib/warden/auth0/version.rb
|
238
|
+
- warden-auth0.gemspec
|
239
|
+
homepage: https://github.com/sarakola/warden-jwt_auth
|
240
|
+
licenses:
|
241
|
+
- MIT
|
242
|
+
metadata:
|
243
|
+
rubygems_mfa_required: 'true'
|
244
|
+
post_install_message:
|
245
|
+
rdoc_options: []
|
246
|
+
require_paths:
|
247
|
+
- lib
|
248
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
249
|
+
requirements:
|
250
|
+
- - ">="
|
251
|
+
- !ruby/object:Gem::Version
|
252
|
+
version: '0'
|
253
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - ">="
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
requirements: []
|
259
|
+
rubygems_version: 3.4.19
|
260
|
+
signing_key:
|
261
|
+
specification_version: 4
|
262
|
+
summary: Auth0 authentication for Warden.
|
263
|
+
test_files: []
|