class Kemal::Hmac::Handler

Overview

This middleware adds hmac support to your application. Returns 401 "Unauthorized" with wrong credentials.

hmac_auth({"my_client" => ["my_secret"]})

HTTP::Server::Context#authorized_hmac_client? is set when the client is authorized.

Defined in:

kemal-hmac/handler.cr

Constructors

Instance Method Summary

Constructor Detail

def self.new(hmac_secrets : Hash(String, Array(String)) = {} of String => Array(String), hmac_client_header : String | Nil = nil, hmac_timestamp_header : String | Nil = nil, hmac_token_header : String | Nil = nil, timestamp_second_window : Int32 | Nil = nil, rejected_code : Int32 | Nil = nil, rejected_message_prefix : String | Nil = nil, hmac_key_suffix_list : Array(String) | Nil = nil, hmac_key_delimiter : String | Nil = nil, hmac_algorithm : String | Nil = nil, enable_env_lookup : Bool = false) #

initialize the Kemal::Hmac::Handler note: "BLUE" and "GREEN" in this context are two different secrets for the same client. This is a common pattern to allow for key rotation without downtime. examples: hmac_secrets: {"cool-client-service" => ["BLUE_SECRET", "GREEN_SECRET"]} - explicitly set secrets for one or many clients hmac_client_header: "HTTP_X_HMAC_CLIENT" hmac_timestamp_header: "HTTP_X_HMAC_TIMESTAMP" hmac_token_header: "HTTP_X_HMAC_TOKEN" timestamp_second_window: 30 rejected_code: 401 rejected_message_prefix: "Unauthorized:" hmac_key_suffix_list: ["HMAC_SECRET_BLUE", "HMAC_SECRET_GREEN"] - only used for env variable lookups hmac_key_delimiter: "_" - only used for env variable lookups hmac_algorithm: "SHA256" enable_env_lookup: true (this value is set to false by default)


[View source]

Instance Method Detail

def call(context) #

[View source]
def fetch_hmac_algorithm(algorithm : String | Nil) : OpenSSL::Algorithm #

[View source]
def load_hmac_headers(context) : Hash(String, String | Nil) #

Load the required headers from the request for hmac authentication


[View source]
def load_secrets(client : String) : Array(String) #

Load the secrets for the given client Returns an array of strings (secrets) with all posible secrets for the given client (BLUE + GREEN)


[View source]
def normalize_client_hash(dict : Hash(String, Array(String))) : Hash(String, Array(String)) #

A helper method to upcase all the keys in a dictionary This ensures that client names passed in via headers exactly match the keys in the secrets cache


[View source]
def recent_timestamp?(timestamp : String, seconds : Int32) : NamedTuple(valid: Bool, message: String) #

Check if the timestamp is within the last seconds seconds and not in the future Timestamps should only be in UTC iso8601 format: 2022-09-27 18:00:00.000 Used to protect against replay attacks


[View source]
def valid_token?(request_token, secret, client, path, timestamp) #

Check the request token by building our own with our known metadata and secret request_token token provided in request secret secret used to build token client client name used to build token path path used to build token timestamp timestamp used to build token returns True if token matches, False otherwise


[View source]
def validate_hmac_headers(headers : Hash(String, String | Nil)) : Array(Array(String)) #

If any of the required headers are missing or empty, return the missing or empty headers


[View source]