amzn/amazon-instant-access-sdk-ruby

Name: amazon-instant-access-sdk-ruby

Owner: Amazon

Description: Ruby SDK to aid in third-party integration with Instant Access

Created: 2017-03-24 19:01:15.0

Updated: 2018-03-03 09:44:01.0

Pushed: 2018-03-13 18:45:01.0

Homepage:

Size: 15

Language: Ruby

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Amazon Instant Access - Ruby SDK

Amazon Instant Access (AIA) is a digital content fulfillment technology that allows purchases on the Amazon website and delivery by third party vendors. This Ruby SDK provides the vendors a simple way to authenticate incoming requests from Amazon. Please refer to our integration guide for Subscriptions (SaaS) or One-Time Purchasing to learn about the on-boarding procedure and the API specifications before using this SDK.

Installation

Run the following set of commands to install the latest version from GitHub:

it clone https://github.com/amzn/amazon-instant-access-sdk-ruby.git
d amazon-instant-access-sdk-ruby
em build amazon-instant-access.gemspec
em install amazon-instant-access-*.gem

Note that sudo may be required depending on the environment.

Getting Started

This instruction assumes that the vendor has already started implementing the web service for handling HTTP requests from Amazon Instant Access, and is already familiar with the integration API. The SDK is for authenticating account linking and fulfillment (service) requests from Amazon.

Here is a simple example of Ruby on Rails controller a vendor might start out with:

s VendorFulfillmentController < ApplicationController

f create
operation = params['operation']
if operation == 'Purchase'
  # Vendor logic
elsif operation == 'Revoke'
  # Vendor logic
elsif operation == 'SubscriptionActivate'
  # Vendor logic
elsif operation == 'SubscriptionDeactivate'
  # Vendor logic
end
render json: {response: 'OK'}, status: :ok
d


Use the SDK to enable authentication in the controller:

ire 'amazon-instant-access'

s VendorFulfillmentController < ApplicationController

f create
credentials = {'public_key' => 'secret_key'}
auth = AmazonInstantAccess::Authentication.new(credentials)
auth.verify_request(
  request.method,
  request.url,
  request.raw_post,
  request.headers
)

operation = params['operation']
if operation == 'Purchase'
  # Vendor logic
elsif operation == 'Revoke'
  # Vendor logic
elsif operation == 'SubscriptionActivate'
  # Vendor logic
elsif operation == 'SubscriptionDeactivate'
  # Vendor logic
end
render json: {response: 'OK'}, status: :ok
d


The signature of the method AmazonInstantAccess::Authentication.verify_request is as follows:

.verify_request(
quest.method,   # [String] HTTP method of the request (e.g. 'POST')
quest.url,      # [String] full URL of the request (e.g. 'https://vendor.com/api/fulfillment')
quest.raw_post, # [String] raw body (payload) of the request
quest.headers   # [Object] an object or hash representing the headers (must allow case-insensitive, string key based access)

Note that the example above is specific to Ruby on Rails, and the method arguments may have to be modified depending on the web framework in use by the vendor. The credentials should not be hardcoded but obtained from a secure, external source (e.g. file with correct permissions).

Logging

Once set up, the AmazonInstantAccess::Authentication instance will automatically compute and verify the request signature. It will also log detailed messages to ./amazon_instant_access_auth.log. The location of the log file and the logging behavior can be customized by passing in a new logger instance into the initializer:

ire 'logger'
ire 'amazon-instant-access'

s VendorFulfillmentController < ApplicationController

f create
credentials = {'public_key' => 'secret_key'}

# Create a custom logger
custom_logger = Logger.new('vendor_custom_log.log')

# Pass in the logger into the initializer to override the default one
auth = AmazonInstantAccess::Authentication.new(credentials, custom_logger)
auth.verify_request(
  request.method,
  request.url,
  request.raw_post,
  request.headers
)

operation = params['operation']
if operation == 'Purchase'
  # Vendor logic
elsif operation == 'Revoke'
  # Vendor logic
elsif operation == 'SubscriptionActivate'
  # Vendor logic
elsif operation == 'SubscriptionDeactivate'
  # Vendor logic
end
render json: {response: 'OK'}, status: :ok
d


Error Handling

If the authentication fails for any reason, the AmazonInstanceAccess::Authentication instance will raise exceptions specific to the issue. These should be caught and handled appropriately by the vendors. Here is an example showing all exceptions that are designed to be thrown by the SDK:

ire 'amazon-instant-access'

s VendorFulfillmentController < ApplicationController

f create
credentials = {'public_key' => 'secret_key'}
auth = AmazonInstantAccess::Authentication.new(credentials)

# Handle authentication failures using a try-catch
request_successfully_verified = false
begin
    auth.verify_request(
      request.method,
      request.url,
      request.raw_post,
      request.headers
    )
rescue AmazonInstantAccess::MissingHeaderError => error
  puts "The request is missing an important header: #{error.message}"
rescue AmazonInstantAccess::MalformedAuthHeaderError => error
  puts "The 'Authorization' header is malformed: #{error.message}"
rescue AmazonInstantAccess::ExpiredRequestError
  puts 'The request is now expired'
rescue AmazonInstantAccess::IncorrectSignatureError
  puts 'The request signature does not match the expected one'
rescue AmazonInstantAccess::UnknownPublicKeyError
  puts 'The request contains an unknown public key'
rescue AmazonInstantAccess::UnsupportedAlgorithmError
  puts 'The request had an invalid hash algorithm (only HMAC SHA256 supported currently)'
else
  request_successfully_verified = true
end

if request_successfully_verified
    operation = params['operation']
    if operation == 'Purchase'
      # Vendor logic
    elsif operation == 'Revoke'
      # Vendor logic
    elsif operation == 'SubscriptionActivate'
      # Vendor logic
    elsif operation == 'SubscriptionDeactivate'
      # Vendor logic
    end
    render json: {response: 'OK'}, status: :ok
else
    render json: {response: 'FAIL_OTHER'}, status: :bad_request
end
d


Alternatively, the parent exception AmazonInstantAccess::AuthenticationError can be caught to reduce verbosity:

ire 'amazon-instant-access'

s VendorFulfillmentController < ApplicationController

f create
credentials = {'public_key' => 'secret_key'}
auth = AmazonInstantAccess::Authentication.new(credentials)

request_successfully_verified = false
begin
    auth.verify_request(
      request.method,
      request.url,
      request.raw_post,
      request.headers
    )
rescue AmazonInstantAccess::AuthenticationError => error
  puts "Authentication failed: #{error.message}"
else
  request_successfully_verified = true
end

if request_successfully_verified
    operation = params['operation']
    if operation == 'Purchase'
      # Vendor logic
    elsif operation == 'Revoke'
      # Vendor logic
    elsif operation == 'SubscriptionActivate'
      # Vendor logic
    elsif operation == 'SubscriptionDeactivate'
      # Vendor logic
    end
    render json: {response: 'OK'}, status: :ok
else
    render json: {response: 'FAIL_OTHER'}, status: :bad_request
end
d


Credentials

If multiple credentials are required, simply add them into the input credentials on initialization:

entials = {
ublic_key1' => 'secret_key1',
ublic_key2' => 'secret_key2',
ublic_key3' => 'secret_key3',
.

 = AmazonInstantAccess::Authentication.new(credentials)
Contact

Send an email to d3-support@amazon.com for technical support and any other enquiries on the SDK. Please include your company name in the subject line to make tracking easier.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.