grape-jwt-authentication 1.0.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.
- 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
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "grape/jwt/authentication"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/doc/assets/logo.png
ADDED
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'grape/jwt/authentication/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'grape-jwt-authentication'
|
9
|
+
spec.version = Grape::Jwt::Authentication::VERSION
|
10
|
+
spec.authors = ['Hermann Mayer']
|
11
|
+
spec.email = ['hermann.mayer92@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'A reusable Grape JWT authentication concern'
|
14
|
+
spec.description = 'A reusable Grape JWT authentication concern'
|
15
|
+
spec.homepage = 'https://github.com/hausgold/grape-jwt-authentication'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = 'exe'
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
|
+
spec.add_development_dependency 'simplecov', '~> 0.15'
|
28
|
+
spec.add_development_dependency 'vcr', '~> 3.0'
|
29
|
+
spec.add_development_dependency 'webmock', '~> 3.1'
|
30
|
+
spec.add_development_dependency 'timecop', '~> 0.9.1'
|
31
|
+
spec.add_development_dependency 'rack', '~> 2.0'
|
32
|
+
spec.add_development_dependency 'rack-test', '~> 0.8.2'
|
33
|
+
|
34
|
+
spec.add_runtime_dependency 'activesupport', '>= 3.2.0'
|
35
|
+
spec.add_runtime_dependency 'grape', '~> 1.0'
|
36
|
+
spec.add_runtime_dependency 'httparty'
|
37
|
+
spec.add_runtime_dependency 'jwt', '~> 2.1'
|
38
|
+
spec.add_runtime_dependency 'recursive-open-struct', '~> 1.0'
|
39
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/concern'
|
5
|
+
require 'active_support/configurable'
|
6
|
+
require 'active_support/cache'
|
7
|
+
require 'active_support/core_ext/hash'
|
8
|
+
require 'active_support/time'
|
9
|
+
require 'active_support/time_with_zone'
|
10
|
+
|
11
|
+
require 'jwt'
|
12
|
+
|
13
|
+
require 'grape'
|
14
|
+
require 'grape/jwt/authentication/version'
|
15
|
+
require 'grape/jwt/authentication/configuration'
|
16
|
+
require 'grape/jwt/authentication/jwt_handler'
|
17
|
+
require 'grape/jwt/authentication/jwt'
|
18
|
+
require 'grape/jwt/authentication/rsa_public_key'
|
19
|
+
|
20
|
+
module Grape
|
21
|
+
module Jwt
|
22
|
+
# The Grape JWT authentication concern.
|
23
|
+
module Authentication
|
24
|
+
extend ActiveSupport::Concern
|
25
|
+
include Grape::DSL::API
|
26
|
+
|
27
|
+
class << self
|
28
|
+
attr_writer :configuration
|
29
|
+
end
|
30
|
+
|
31
|
+
# Retrieve the current configuration object.
|
32
|
+
#
|
33
|
+
# @return [Configuration]
|
34
|
+
def self.configuration
|
35
|
+
@configuration ||= Configuration.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# Configure the concern by providing a block which takes
|
39
|
+
# care of this task. Example:
|
40
|
+
#
|
41
|
+
# Grape::Jwt::Authentication.configure do |conf|
|
42
|
+
# # conf.xyz = [..]
|
43
|
+
# end
|
44
|
+
def self.configure
|
45
|
+
yield(configuration)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Reset the current configuration with the default one.
|
49
|
+
def self.reset_configuration!
|
50
|
+
self.configuration = Configuration.new
|
51
|
+
end
|
52
|
+
|
53
|
+
included do
|
54
|
+
# Configure a new Grape authentication strategy which will be
|
55
|
+
# backed by the JwtHandler middleware. We do not want
|
56
|
+
# gem-internal claim verification or database lookup
|
57
|
+
# functionality. Let the user handle this the way he want.
|
58
|
+
Grape::Middleware::Auth::Strategies.add(:jwt,
|
59
|
+
JwtHandler,
|
60
|
+
->(opts) { [opts] })
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Jwt
|
5
|
+
module Authentication
|
6
|
+
# The configuration for the Grape JWT authentication concern.
|
7
|
+
class Configuration
|
8
|
+
include ActiveSupport::Configurable
|
9
|
+
|
10
|
+
# The authenticator function which must be defined by the user to
|
11
|
+
# verify the given JSON Web Token. Here comes all your logic to lookup
|
12
|
+
# the related user on your database, the token claim verification
|
13
|
+
# and/or the token cryptographic signing. The function must return true
|
14
|
+
# or false to indicate the validity of the token.
|
15
|
+
#
|
16
|
+
# Grape::Jwt::Authentication.configure do |conf|
|
17
|
+
# conf.authenticator = proc do |token|
|
18
|
+
# # Verify the token the way you like.
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
config_accessor(:authenticator) { proc { false } }
|
22
|
+
|
23
|
+
# Whenever the given value on the +Authorization+ header is not a valid
|
24
|
+
# Bearer authentication scheme or the token itself is not a valid JSON
|
25
|
+
# Web Token, this user defined function will be called. You can add
|
26
|
+
# custom handling of this situations, like responding different HTTP
|
27
|
+
# status code, or bodies. By default the Rack stack will be interrupted
|
28
|
+
# and a response with the 400 Bad Request status code will be send to
|
29
|
+
# the client. The raw token (value of the +Authorization+ header) and
|
30
|
+
# the Rack app will be injected to your function for maximum
|
31
|
+
# flexibility.
|
32
|
+
#
|
33
|
+
# Grape::Jwt::Authentication.configure do |conf|
|
34
|
+
# conf.malformed_auth_handler = proc do |raw_token, app|
|
35
|
+
# # Do your own error handling.
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
config_accessor(:malformed_auth_handler) do
|
39
|
+
proc do |_raw_token, _app|
|
40
|
+
[400, {}, ['Authorization header is malformed.']]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# When the client sends a corrected formatted JSON Web Token with the
|
45
|
+
# Bearer authentication scheme within the +Authorization+ header and
|
46
|
+
# your authenticator fails for some reason (token claims, wrong
|
47
|
+
# audience, bad subject, expired token, wrong cryptographic signing
|
48
|
+
# etc), this function is called to handle the bad authentication. By
|
49
|
+
# default the Rack stack will be interrupted and a response with the
|
50
|
+
# 401 Unauthorized status code will be send to the client. You can
|
51
|
+
# customize this the way you like and send different error codes, or
|
52
|
+
# handle the error completely different. The parsed JSON Web Token and
|
53
|
+
# the Rack app will be injected to your function to allow any
|
54
|
+
# customized error handling.
|
55
|
+
#
|
56
|
+
# Grape::Jwt::Authentication.configure do |conf|
|
57
|
+
# conf.failed_auth_handler = proc do |token, app|
|
58
|
+
# # Do your own error handling.
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
config_accessor(:failed_auth_handler) do
|
62
|
+
proc do |_token, _app|
|
63
|
+
[401, {}, ['Access denied.']]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Whenever you want to use the {RsaPublicKey} class you configure the
|
68
|
+
# default URL on the singleton instance, or use the gem configure
|
69
|
+
# method and set it up accordingly. We allow the fetch of the public
|
70
|
+
# key from a remote server (HTTP/HTTPS) or from a local file which is
|
71
|
+
# accessible by the ruby process. Specify the URL or the local path
|
72
|
+
# here.
|
73
|
+
config_accessor(:rsa_public_key_url) { nil }
|
74
|
+
|
75
|
+
# You can preconfigure the {RsaPublickey} class to enable/disable
|
76
|
+
# caching. For a remote public key location it is handy to cache the
|
77
|
+
# result for some time to keep the traffic low to this resource server.
|
78
|
+
# For a local file you can skip this.
|
79
|
+
config_accessor(:rsa_public_key_caching) { false }
|
80
|
+
|
81
|
+
# When you make use of the caching of the {RsaPublicKey} class you can
|
82
|
+
# fine tune the expiration time of this cache. The RSA public key from
|
83
|
+
# your identity provider should not change this frequent, so a cache
|
84
|
+
# for at least one hour is fine. You should not set it lower than one
|
85
|
+
# minute. Keep this setting in mind when you change keys. Your
|
86
|
+
# infrastructure could be inoperable for this configured time.
|
87
|
+
config_accessor(:rsa_public_key_expiration) { 1.hour }
|
88
|
+
|
89
|
+
# The JSON Web Token isser which should be used for verification.
|
90
|
+
config_accessor(:jwt_issuer) { nil }
|
91
|
+
|
92
|
+
# The resource server (namely the one which configures this right now)
|
93
|
+
# which MUST be present on the JSON Web Token audience claim.
|
94
|
+
config_accessor(:jwt_beholder) { nil }
|
95
|
+
|
96
|
+
# You can configure a different JSON Web Token verification option hash
|
97
|
+
# if your algorithm differs or you want some extra/different options.
|
98
|
+
# Just watch out that you have to pass a proc to this configuration
|
99
|
+
# property. On the {Grape::Jwt::Authentication::Jwt} class it has to be
|
100
|
+
# a simple hash. The default is here the RS256 algorithm with enabled
|
101
|
+
# expiration check, and issuer+audience check when the
|
102
|
+
# {jwt_issuer}/{jwt_beholder} are configured accordingly.
|
103
|
+
config_accessor(:jwt_options) do
|
104
|
+
proc do
|
105
|
+
conf = Grape::Jwt::Authentication.configuration
|
106
|
+
{ algorithm: 'RS256',
|
107
|
+
exp_leeway: 30.seconds.to_i,
|
108
|
+
iss: conf.jwt_issuer,
|
109
|
+
verify_iss: !conf.jwt_issuer.nil?,
|
110
|
+
aud: conf.jwt_beholder,
|
111
|
+
verify_aud: !conf.jwt_beholder.nil?,
|
112
|
+
# @TODO: https://github.com/jwt/ruby-jwt/issues/247
|
113
|
+
verify_iat: false }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# You can configure your own verification key on the Jwt wrapper class.
|
118
|
+
# This way you can pass your HMAC secret or your ECDSA public key to
|
119
|
+
# the JSON Web Token validation method. Here you need to pass a proc,
|
120
|
+
# on the {Grape::Jwt::Authentication::Jwt} class it has to be a scalar
|
121
|
+
# value. By default we use the
|
122
|
+
# {Grape::Jwt::Authentication::RsaPublicKey} class to retrieve the RSA
|
123
|
+
# public key.
|
124
|
+
config_accessor(:jwt_verification_key) do
|
125
|
+
proc { RsaPublicKey.instance.fetch }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'recursive-open-struct'
|
4
|
+
|
5
|
+
module Grape
|
6
|
+
module Jwt
|
7
|
+
module Authentication
|
8
|
+
# A easy to use model for verification of JSON Web Tokens. This is just a
|
9
|
+
# wrapper class for the excellent ruby-jwt gem. It's completely up to you
|
10
|
+
# to use it. But be aware, its a bit optinionated by default.
|
11
|
+
class Jwt
|
12
|
+
# All the following JWT verification issues lead to a failed validation.
|
13
|
+
RESCUE_JWT_EXCEPTIONS = [
|
14
|
+
::JWT::DecodeError,
|
15
|
+
::JWT::VerificationError,
|
16
|
+
::JWT::ExpiredSignature,
|
17
|
+
::JWT::IncorrectAlgorithm,
|
18
|
+
::JWT::ImmatureSignature,
|
19
|
+
::JWT::InvalidIssuerError,
|
20
|
+
::JWT::InvalidIatError,
|
21
|
+
::JWT::InvalidAudError,
|
22
|
+
::JWT::InvalidSubError,
|
23
|
+
::JWT::InvalidJtiError,
|
24
|
+
::JWT::InvalidPayload
|
25
|
+
].freeze
|
26
|
+
|
27
|
+
# :reek:Attribute because its fine to be extern-modifiable at these
|
28
|
+
# instances
|
29
|
+
attr_reader :payload, :token
|
30
|
+
attr_writer :verification_key, :jwt_options
|
31
|
+
attr_accessor :issuer, :beholder
|
32
|
+
|
33
|
+
# Setup a new JWT instance. You have to pass the raw JSON Web Token to
|
34
|
+
# the initializer. Example:
|
35
|
+
#
|
36
|
+
# Jwt.new('j.w.t')
|
37
|
+
# # => <Jwt>
|
38
|
+
#
|
39
|
+
# @return [Jwt]
|
40
|
+
def initialize(token)
|
41
|
+
parsed_payload = JWT.decode(token, nil, false).first.symbolize_keys
|
42
|
+
@token = token
|
43
|
+
@payload = RecursiveOpenStruct.new(parsed_payload)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Checks if the payload says this is a refresh token.
|
47
|
+
#
|
48
|
+
# @return [Boolean] Whenever this is a access token
|
49
|
+
def access_token?
|
50
|
+
payload.typ == 'access'
|
51
|
+
end
|
52
|
+
|
53
|
+
# Checks if the payload says this is a refresh token.
|
54
|
+
#
|
55
|
+
# @return [Boolean] Whenever this is a refresh token
|
56
|
+
def refresh_token?
|
57
|
+
payload.typ == 'refresh'
|
58
|
+
end
|
59
|
+
|
60
|
+
# Retrives the expiration date from the payload when set.
|
61
|
+
#
|
62
|
+
# @return [nil|ActiveSupport::TimeWithZone] The expiration date
|
63
|
+
def expires_at
|
64
|
+
exp = payload.exp
|
65
|
+
return nil unless exp
|
66
|
+
Time.zone.at(exp)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Deliver the public key for verification by default. This uses the
|
70
|
+
# {RsaPublicKey} class, but you can configure the verification key the
|
71
|
+
# way you like. (Especially for different algorithms, like HMAC or
|
72
|
+
# ECDSA) Just make use of the same named setter.
|
73
|
+
#
|
74
|
+
# @return [OpenSSL::PKey::RSA|Mixed] The verification key
|
75
|
+
def verification_key
|
76
|
+
unless @verification_key
|
77
|
+
conf = Grape::Jwt::Authentication.configuration
|
78
|
+
return conf.jwt_verification_key.call
|
79
|
+
end
|
80
|
+
@verification_key
|
81
|
+
end
|
82
|
+
|
83
|
+
# This getter passes back the default JWT verification option hash
|
84
|
+
# which is optinionated. You can change this the way you like by
|
85
|
+
# configuring your options with the help of the same named setter.
|
86
|
+
#
|
87
|
+
# @return [Hash] The JWT verification options hash
|
88
|
+
def jwt_options
|
89
|
+
unless @jwt_options
|
90
|
+
conf = Grape::Jwt::Authentication.configuration
|
91
|
+
return conf.jwt_options.call
|
92
|
+
end
|
93
|
+
@jwt_options
|
94
|
+
end
|
95
|
+
|
96
|
+
# Verify the current token by our hard and strict rules. Whenever the
|
97
|
+
# token was not parsed from a string, we encode the current state to a
|
98
|
+
# JWT string representation and check this.
|
99
|
+
#
|
100
|
+
# @return [Boolean] Whenever the token is valid or not
|
101
|
+
#
|
102
|
+
# :reek:NilCheck because we have to check the token
|
103
|
+
# origin and react on it
|
104
|
+
def valid?
|
105
|
+
JWT.decode(token, verification_key, true, jwt_options) && true
|
106
|
+
rescue *RESCUE_JWT_EXCEPTIONS
|
107
|
+
false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Jwt
|
5
|
+
module Authentication
|
6
|
+
# Take care of the token validation and verification on this
|
7
|
+
# Rack middleware. It is a self contained implementation of a
|
8
|
+
# valid Rack handler which checks for a common JWT token
|
9
|
+
# Authorization header and calls a user given verification block
|
10
|
+
# which performs the database lookup or whatever is necessary
|
11
|
+
# for the verification.
|
12
|
+
class JwtHandler
|
13
|
+
# A internal exception handling for failed authentications.
|
14
|
+
class AuthenticationError < StandardError; end
|
15
|
+
# A internal exception handling for malformed headers.
|
16
|
+
class MalformedHeaderError < StandardError; end
|
17
|
+
|
18
|
+
# A common JWT validation regex which meets the RFC specs.
|
19
|
+
JWT_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/
|
20
|
+
|
21
|
+
# Initialize a new Rack middleware for Bearer token
|
22
|
+
# processing.
|
23
|
+
#
|
24
|
+
# @param app [Proc] The regular Rack application
|
25
|
+
# @param options [Hash] A global-overwritting configuration hash
|
26
|
+
def initialize(app, options = {})
|
27
|
+
@app = app
|
28
|
+
@options = options
|
29
|
+
end
|
30
|
+
|
31
|
+
# A shared configuration lookup helper which selects the requested
|
32
|
+
# entry from the local or global configuration object. The local
|
33
|
+
# configuration takes presedence over the global one.
|
34
|
+
#
|
35
|
+
# @param key [Symbol] The local config key
|
36
|
+
# @param global_key [Symbol] The global config key
|
37
|
+
# @return [Mixed] The configuration value
|
38
|
+
def config(key, global_key)
|
39
|
+
block = @options[key]
|
40
|
+
unless block
|
41
|
+
global_conf = Grape::Jwt::Authentication.configuration
|
42
|
+
return global_conf.send(global_key)
|
43
|
+
end
|
44
|
+
block
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get the local or global defined authenticator for the JWT handler.
|
48
|
+
#
|
49
|
+
# @return [Proc] The authenticator block
|
50
|
+
def authenticator
|
51
|
+
config(:proc, :authenticator)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get the local or global defined malformed authentication handler for
|
55
|
+
# the JWT handler.
|
56
|
+
#
|
57
|
+
# @return [Proc] The malformed authorization handler block
|
58
|
+
def malformed_handler
|
59
|
+
config(:malformed, :malformed_auth_handler)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the local or global defined failed authentication handler for the
|
63
|
+
# JWT handler.
|
64
|
+
#
|
65
|
+
# @return [Proc] The failed authentication handler block
|
66
|
+
def failed_handler
|
67
|
+
config(:failed, :failed_auth_handler)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Validate the Bearer authentication scheme on the given
|
71
|
+
# authorization header and validate the JWT token when it was
|
72
|
+
# found.
|
73
|
+
#
|
74
|
+
# @param header [String] The authorization header value
|
75
|
+
# @return [String] The parsed and well-formatted JWT
|
76
|
+
def parse_token(header)
|
77
|
+
token = header.to_s.scan(/^Bearer (.*)/).flatten.first
|
78
|
+
raise MalformedHeaderError unless JWT_REGEX =~ token
|
79
|
+
token
|
80
|
+
end
|
81
|
+
|
82
|
+
# Perform the authentication logic on the Rack compatible
|
83
|
+
# interface.
|
84
|
+
#
|
85
|
+
# :reek:TooManyStatements because reek counts exception
|
86
|
+
# handling as statements
|
87
|
+
def call(env)
|
88
|
+
# Unfortunately Grape's middleware stack orders the error
|
89
|
+
# handling higher than the formatter. So when a error is
|
90
|
+
# raised, the Rack env was not yet analysed and the content
|
91
|
+
# type not negotiated. This would result in allways-JSON
|
92
|
+
# responses on authentication errors. We want to be smarter
|
93
|
+
# here and respond in the requested format on authentication
|
94
|
+
# errors, that why we invoke the formatter middleware here.
|
95
|
+
Grape::Middleware::Formatter.new(->(_) {}).call(env)
|
96
|
+
|
97
|
+
# Parse the JWT token and give it to the user defined block
|
98
|
+
# for futher verification. The user given block MUST return
|
99
|
+
# a positive result to allow the request to be further
|
100
|
+
# processed, or a negative result to stop processing.
|
101
|
+
token = parse_token(env['HTTP_AUTHORIZATION'])
|
102
|
+
raise AuthenticationError unless authenticator.call(token)
|
103
|
+
|
104
|
+
# Looks like we are on a good path and the given token was
|
105
|
+
# valid on all checks. So we continue the regular
|
106
|
+
# application logic now.
|
107
|
+
@app.call(env)
|
108
|
+
rescue MalformedHeaderError
|
109
|
+
# Call the user defined malformed authentication handler.
|
110
|
+
malformed_handler.call(env['HTTP_AUTHORIZATION'], @app)
|
111
|
+
rescue AuthenticationError
|
112
|
+
# Call the user defined failed authentication handler.
|
113
|
+
failed_handler.call(token, @app)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|