sigaws v0.7.2 Sigaws

A library to sign and verify HTTP requests using AWS Signature V4.

Inline docs

Sigaws does not dictate how you compose and send HTTP requests. You can use HTTPoison or any other HTTP client to do that. The signing functions in this library work with the HTTP request information provided and return an Elixir map containing signature related parameters/headers. Similarly, the verification works with the request information and a provider to perform verification.

Take look at plug_sigaws, a plug built using this library. This plug can be added to your API pipeline to protect your API endpoints. It can also be added to browser pipelines to protect access to web resources using “presigned” URLs with access expiration.

Examples

Signature to be passed as request headers

url = "http://api.endpoint.host:5000/somthing?a=10&b=20"
headers = %{"header1" => "value1", "header2" => "value2"}
{:ok, %{} = sig_data, _} =
  Sigaws.sign_req(url,
                  headers: headers,
                  region: "delta-quad",
                  service: "my-service",
                  access_key: "some-access-key",
                  secret: "some-secret")

{:ok, resp} = HTTPoison.get(url, Map.merge(headers, sig_data))

Signature to be passed in query string (“presigned” URL)

url = "http://api.endpoint.host:5000/somthing?a=10&b=20"
{:ok, %{} = sig_data, _} =
  Sigaws.sign_url(url,
                  body: :unsigned,
                  expires_in: 5 * 60,                 # 5 minutes
                  region: "delta-quad",
                  service: "my-service",
                  access_key: "some-access-key",
                  secret: "some-secret")

presigned_url = Sigaws.Util.add_params_to_url(url, sig_data)

Signature Verification

The verification process relies on a provider module that implements Sigaws.Provider behavior. The provider is expected to supply the signing key based on the information present in the context (primarily the access key).

{:ok, %Sigaws.Ctxt{} = ctxt} =
  Sigaws.Verify(conn.request_path,
    method: conn.method,
    params: conn.query_params,
    headers: conn.req_headers,
    body: get_raw_body(conn),
    provider: SigawsQuickStartProvider)

Checkout this Blog post that shows how to protect Phoenix built REST APIs using plug_sigaws and sigaws_quickstart_provider Hex packages.

Link to this section Summary

Functions

Sign the given HTTP request and return the signature data to be treated as request headers

Presign the given URL and return the signature data to be treated as query parameters

Verify the signature of the given HTTP request data

Link to this section Functions

Link to this function sign_req(url, additional_named_input)
sign_req(binary(), keyword()) ::
  {:ok, map(), map()} |
  {:error, atom(), binary()}

Sign the given HTTP request and return the signature data to be treated as request headers.

NameDescription
:methodA string value — GET, POST, PUT, etc (defaults to GET)
:params
 
A map of query parameters — merged with the query string in the given url (defaults to an empty map)
:headersA map of request headers (defaults to an empty map)
:body
 
A string value (use appropriate encoder) or :unsigned or {:content_hash, hash} (defaults to an empty string)
:signed_at
 
DateTime in UTC or a string in the form YYYMMDDTHHmmSSZ (defults to current time in UTC)
:expires_inOptional expiration in seconds since the signing time
:regionA string value
:serviceA string value
:access_key
 
Access key ID used for signing (defaults to AWS_ACCESS_KEY_ID environment variable)
:signing_keyA signing key can be provided instead of a secret key
:secret
 
Used when signing key is not provided (defaults to AWS_SECRET_ACCESS_KEY environment variable)
:normalize_pathRefer to Section 5.2 in RFC 3986 (default is false)

When there are no errors in signing, this function returns: {:ok, sig_data, info} The signature data returned in sig_data map include the following:

  • X-Amz-Algorithm
  • X-Amz-Date
  • X-Amz-SignedHeaders
  • Authorization

The third item info is also a map. When the MIX environment is either :dev or :test, this info map contains the canonical request (c_req) and the string to sign (sts) computed during the signature generation. In all other MIX environments (including :prod) this info will be an empty map.

Error Returns
{:error, :invalid_input, _}
{:error, :invalid_data, _}
Link to this function sign_url(url, additional_named_input)
sign_url(binary(), keyword()) ::
  {:ok, map(), map()} |
  {:error, atom(), binary()}

Presign the given URL and return the signature data to be treated as query parameters.

Refer to sign_req/2 for the named input that can be passed along with the URL. The returned sig_data should be merged with any existing query parameters in the URL while sending the request to the server. (Checkout the examples at the top.)

When there are no errors in signing, this function returns: {:ok, sig_data, info} The sig_data map returned includes the following query parameters:

  • X-Amz-Algorithm
  • X-Amz-Content-Sha256
  • X-Amz-Credential
  • X-Amz-Date
  • X-Amz-SignedHeaders
  • X-Amz-Signature
Link to this function verify(req_path, opts)
verify(binary(), keyword()) ::
  {:ok, Sigaws.Ctxt.t()} |
  {:error, atom(), binary()}

Verify the signature of the given HTTP request data.

The request data passed should include the signature information either in query parameters (presigned request) or in the request headers. Presence of X-Amz-Credential or X-Amz-Signature in the query parameters leads to treatment of the request as a “presigned” request. If not, the signature data are expected to be in the Authorization and other headers.

NameDescription
:methodOptional string value — GET, POST, PUT, etc (defaults to GET)
:query_stringOptional string value (defaults to empty string)
:paramsOptinal query parameters (defaults to empty map)
:headersOptional request headers (defaults to empty map)
:body
 
Optional raw body — not decoded values such as JSON (defaults to empty string)
:providerModule that implements Sigaws.Provider behavior — required
:normalize_pathRefer to Section 5.2 in RFC 3986 (default is false)

Upon successful signature verification this function returns {:ok, %Sigaws.Ctxt{} = ctxt}. The returned context Sigaws.Ctx can be used to make further policy decisions if desired.

Error Returns
{:error, :invalid_input, _}
{:error, :invalid_data, _}
{:error, :missing_data, _}
{:error, :verification_failed, ""}
{:error, :mismatched, "X-Amz-Date"}