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