lib/grape/jwt/authentication/jwt_handler.rb in grape-jwt-authentication-1.0.1 vs lib/grape/jwt/authentication/jwt_handler.rb in grape-jwt-authentication-1.1.0
- old
+ new
@@ -13,12 +13,16 @@
# A internal exception handling for failed authentications.
class AuthenticationError < StandardError; end
# A internal exception handling for malformed headers.
class MalformedHeaderError < StandardError; end
+ # A generic JWT part, the full token contains three parts
+ # separated by a period.
+ JWT_PART_REGEX = /([a-zA-Z0-9\-_]+)?/.freeze
+
# A common JWT validation regex which meets the RFC specs.
- JWT_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/
+ JWT_REGEX = Regexp.new("^#{([JWT_PART_REGEX] * 3).join('\.')}$").freeze
# Initialize a new Rack middleware for Bearer token
# processing.
#
# @param app [Proc] The regular Rack application
@@ -74,16 +78,34 @@
# @param header [String] The authorization header value
# @return [String] The parsed and well-formatted JWT
def parse_token(header)
token = header.to_s.scan(/^Bearer (.*)/).flatten.first
raise MalformedHeaderError unless JWT_REGEX =~ token
+
token
end
+ # Inject the token to the environment as a parsed version. This allows
+ # further usage like extracting the subject from the payload when the
+ # verification was valid.
+ #
+ # @param env [Hash{String => Mixed}] the Rack environment
+ # @param token [String] the token parsed from the HTTP header
+ def inject_token_into_env(env, token)
+ env['grape_jwt_auth.parsed_token'] = Jwt.new(token)
+ rescue *Jwt::RESCUE_JWT_EXCEPTIONS
+ env['grape_jwt_auth.parsed_token'] = nil
+ ensure
+ env['grape_jwt_auth.original_token'] = token
+ end
+
# Perform the authentication logic on the Rack compatible
# interface.
#
+ # @param env [Hash{String => Mixed}] the Rack environment
+ #
+ # rubocop:disable Metrics/AbcSize because thats the auth handling core
# :reek:TooManyStatements because reek counts exception
# handling as statements
def call(env)
# Unfortunately Grape's middleware stack orders the error
# handling higher than the formatter. So when a error is
@@ -92,15 +114,20 @@
# responses on authentication errors. We want to be smarter
# here and respond in the requested format on authentication
# errors, that why we invoke the formatter middleware here.
Grape::Middleware::Formatter.new(->(_) {}).call(env)
- # Parse the JWT token and give it to the user defined block
+ # Parse the JWT token from the request headers.
+ token = parse_token(env['HTTP_AUTHORIZATION'])
+
+ # Inject the parsed token to the Rack environment.
+ inject_token_into_env(env, token)
+
+ # Give the parsed token to the user defined block
# for futher verification. The user given block MUST return
# a positive result to allow the request to be further
# processed, or a negative result to stop processing.
- token = parse_token(env['HTTP_AUTHORIZATION'])
raise AuthenticationError unless authenticator.call(token)
# Looks like we are on a good path and the given token was
# valid on all checks. So we continue the regular
# application logic now.
@@ -110,9 +137,10 @@
malformed_handler.call(env['HTTP_AUTHORIZATION'], @app)
rescue AuthenticationError
# Call the user defined failed authentication handler.
failed_handler.call(token, @app)
end
+ # rubocop:enable Metrics/AbcSize
end
end
end
end