module Authy

Api Authentication Module

How it works

Client Side

A string is first created using your HTTP payload containing all parameters and a preshared key. This string is then used to create the signature which is a Base64 encoded SHA1 HMAC, using the clients private secret key. This signature is then can be added to Authorization HTTP header Authorization = Authy.generate_signed_header(params) You can pass explicite service name and shared_key as an argument to support multiple API authentication Authorization = Authy.generate_signed_header(params, 'client_1', ENV['client_1_shared_key']) Now add this to to your header header["Authorization"] = Authorization

secret_key generated from the server side can be kept inside the a environment variable with name shared_key along with service_name as your service name

Server Side API validation is_valid = Authy.validate_api(params, request.headers) Pass explicite shared key to support multiple API authentication is_valid = Authy.validate_api(params, request.headers,ENV['client_1_shared_key']) Generating secret key for clients secret_key = Authy.generate_secret_key

Public Class Methods

fully_qualified_keys_2(object, fully_qualified_keys = [], val = '', prefix = nil, map = {}) click to toggle source
# File lib/authi.rb, line 70
def self.fully_qualified_keys_2(object, fully_qualified_keys = [], val = '', prefix = nil, map = {})
  if object.is_a? Hash
    object.each do |key, val|
      key_ = prefix.nil? ? key : prefix + '[' + key + ']'
      Authy.fully_qualified_keys_2(val, fully_qualified_keys, val, key_, map)
    end
  elsif object.is_a? Array
    object.each_with_index do |item, index|
      key_ = prefix + '[' + index.to_s + ']'
      Authy.fully_qualified_keys_2(item, fully_qualified_keys, item, key_, map)
    end
  else
    map[prefix] = val.to_s
    fully_qualified_keys << prefix
  end
  [fully_qualified_keys.join(','), map]
end
generate_secret_key() click to toggle source

Generate a pre-shared key for client

Example:

>> Authy.generate_secret_key
=> "63SnNesbvA9IuwXlkpF9KA=="
# File lib/authi.rb, line 115
def self.generate_secret_key
  SecureRandom.base64
end
generate_signed_header(data, service_name = ENV['service_name'], shared_key = ENV['shared_key']) click to toggle source

Create a signed hash using input parameter

Example:

>> Authy.generate_signed_header({ 'key' => value })
=> {:"X-OWNING-SERVICE"=>"l", :"X-SIGNING-ORDER"=>"", :"X-SIGNATURE"=>""}

Arguments:

data: (map)
# File lib/authi.rb, line 36
def self.generate_signed_header(data, service_name = ENV['service_name'], shared_key = ENV['shared_key'])
  processed_data, deep_lookup_table = Authy.fully_qualified_keys(data)
  signing_order = processed_data + ',' + 'owning_service,signing_order'
  request_data = Authy.build_query(processed_data, deep_lookup_table)
  unsigned_data = request_data + \
                  '&owning_service=' + service_name + '&signing_order=' + \
                  signing_order
  digest = OpenSSL::Digest.new('sha1')
  hmac = OpenSSL::HMAC.digest(digest, shared_key, unsigned_data)
  signed_str = Base64.strict_encode64(hmac)
  { 'X-OWNING-SERVICE': service_name, 'X-SIGNING-ORDER': signing_order,
    'X-SIGNATURE': signed_str }
end
validate_api(params, header, shared_key = ENV['shared_key']) click to toggle source

Validate API

Example:

>> Authy.validate_api(params, request.headers)
=> true/false

Arguments:

params: (map)
header
# File lib/authi.rb, line 104
def self.validate_api(params, header, shared_key = ENV['shared_key'])
  owning_service = header['Authorization'][:'X-OWNING-SERVICE']
  expected_header = Authy.generate_signed_header(params, owning_service, shared_key)
  expected_header[:'X-SIGNATURE'] == header['Authorization'][:'X-SIGNATURE']
end