Skip to content

Instantly share code, notes, and snippets.

@heridev
Last active March 29, 2024 21:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heridev/0ec394a5ee569324ac903b3845593716 to your computer and use it in GitHub Desktop.
Save heridev/0ec394a5ee569324ac903b3845593716 to your computer and use it in GitHub Desktop.
How to access request headers in a Rack middleware application? (Rails, Sinatra, etc)

In a Rack-based application, including frameworks built on top of Rack like Ruby on Rails and Sinatra, middleware plays a crucial role in processing HTTP requests and responses. When you're working within a Rack middleware, accessing request headers is straightforward because the request is represented as an environment hash (env) passed to the call method of your middleware.

Here's how to access request headers in different ways within a Rack middleware:

Using Rack::Request.new

app/middleware/user_token_authenticator_middleware.rb

class UserTokenAuthenticatorMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    if (user = find_user_by_token)
      env[:current_user] = user
      @app.call(env)
    else
      [
        401,
        { 'Content-Type' => 'application/json' },
        [{error: 'invalid or missing authentication token '}]
      ]
    end
  end

  def find_user_by_token
    request = Rack::Request.new(env)
 
    from_authorization = requests.headers["Authorization"]&.split&.last
    user_token = request.params["authToken"] || from_authorization

    # Implemented via decoding token and searching by that
    User.find_by_authentication_token?(user_token)
  end
end

Direct access from the env Hash

The most direct way to access request headers in a Rack middleware is by directly referencing the env hash. Rack converts HTTP headers to uppercase, replaces hyphens with underscores, and prefixes them with HTTP_, making them easy to identify and access. For example, to access the Content-Type header, you would do the following:

content_type = env['HTTP_CONTENT_TYPE']

Converting the previous examples to use the env hash it would look like this

class UserTokenAuthenticatorMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    if (user = find_user_by_token)
      env[:current_user = user
      @app.call(env)
    else
      [
        401,
        { 'Content-Type' => 'application/json' },
        [{error: 'invalid or missing authentication token '}]
      ]
    end
  end

  def find_user_by_token
    from_authorization = env["HTTP_AUTHORIZATION"]&.split&.last
    User.find_by_authentication_token?(from_authorization)
  end
end

Accessing request headers in a Rack middleware is primarily done through the env hash, either directly or by wrapping it in a Rack::Request object for convenience and more Ruby-like access patterns.

class UserTokenAuthenticatorMiddleware
def initialize(app)
@app = app
end
def call(env)
if (user = find_user_by_token)
env[:current_user] = user
@app.call(env)
else
[
401,
{ 'Content-Type' => 'application/json' },
[{error: 'invalid or missing authentication token '}]
]
end
end
def find_user_by_token
from_authorization = env["HTTP_AUTHORIZATION"]&.split&.last
User.find_by_token(from_authorization)
end
end
class UserTokenAuthenticatorMiddleware
def initialize(app)
@app = app
end
def call(env)
if (user = find_user_by_token)
env[:current_user] = user
@app.call(env)
else
[
401,
{ 'Content-Type' => 'application/json' },
[{error: 'invalid or missing authentication token '}]
]
end
end
def find_user_by_token
request = Rack::Request.new(env)
from_authorization = requests.headers["Authorization"]&.split&.last
user_token = request.params["authToken"] || from_authorization
# Implemented via decoding token and searching by that
User.find_by_authentication_token?(user_token)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment