You can use hash-based message authentication code (HMAC) to create single use, time-limited signature-based URLs. These URLs enable you to go beyond token-based authentication and put time constraints on your one-time URLs.
Requests That Can Be Signed
All endpoints in the HTTP interface except /account/login accept signed requests:
- /post/directory
- /post/file
- /post/raw
- /multipart/create
- /multipart/piece
- /multipart/complete
Signing and Submitting a Request
This section explains the mechanics of signing and sending a request using
/post/raw
as an example. In this example, a file called testfile.txt
is uploaded to the caller’s namespace. To make the example simple, the only /post/raw
-specific header involved is X-Agile-Basename
. An X-Agile-Directory
header is not sent, causing the file to be created under the root directory.The example assumes you understand the
/post/raw
endpoint. See File Raw Post for additional information.Please note the following generalizations about signing all requests (not just /
post/raw
):- Before signing a request, you must have previously generated your access key and secret using the
initKeyPair
call. See Initializing HMAC Key Pairs for additional information. - Part of the process of signing a request involves creating a query string, which must be URL-encoded. For spaces, use + rather than %20.
- Query string terms must appear in alphabetical order.
- Because your access_key is involved, you do not have to send an
X-Agile-Authorization
header.
Sign the Request
- Construct the request’s query string, adding to it the following:
- An entry for your access key (from the
initKeyPair
call). Example:access_key=3e7359107d65869061992
- A timestamp after which the request will be invalid. Example:
&expiry=1461084890
- An entry for your access key (from the
- Entries for each Edgio-specific HTTP header (and its value) that you will submit with the request. Remove the “X-Agile” prefix from each header name and make the name all lower case. Example:
X-Agile-Basename
with a value of/testfile.txt becomes &basename=testfile.txt
- Place the terms in the query string in ascending order by term key.
- Combine the request’s path and query string, then make an hmac SHA256 digest from the combination using your secret key as the key. For example, make the digest out of this:
/post/raw?access_key=3e7359107d65869061992&basename=testfile.txt&expiry=1461084890
- Then base64 encode the digest from the previous step.
- Add the base64 encoded value to the query string in the signature term like this:
/post/raw?access_key=asdf&basename=testfile.txt&expiry=1461084890&signature= g97jovWlpjTP0u+1VPfWhQa5GGpdW1hf6oApxQWIgXg=
Submit the Request
When you submit the request, you must include:
- the
X-Agile-Signature
header whose value will be the entire path + query string combination. See Sample Python Code - any additional request headers required by the request. Do not pass an
X-Agile-Authorization
header.
Sample Python Code
The following code signs and submits a Post Raw request, but you can use the code as a basis for any other requests that can be signed.
Python
1import requests2import base643import hashlib4import hmac5import io6import os7import time8import argparse91011def make_hmac_signature(headers, endpoint, expiry, access_key, secret_key):12 mac = [13 "access_key={access_key}".format(access_key=access_key),14 "expiry={expiry}".format(expiry=expiry),15 ]16 for header in headers:17 if header.startswith("X-Agile-"):18 mac.append("{key}={value}".format(key=header[len("X-Agile-"):].lower(), value=headers[header]))19 mac.sort()20 payload = "{endpoint}?{query_string}".format(endpoint=endpoint,query_string="&".join(mac))21 raw_signature = hmac.new(secret_key, msg=payload, digestmod=hashlib.sha256).digest()22 signature = payload + "&signature=" + base64.b64encode(raw_signature)23 return signature242526def do_post_raw(local_path, remote_path, access_key, secret_key, host="api.lama.lldns.net"):27 data_stream = io.open(local_path, "rb")28 headers = {29 'X-Agile-Directory': os.path.dirname(remote_path),30 'X-Agile-Basename': os.path.basename(remote_path),31 'X-Agile-Content-Detect': 'name',32 }33 signature = make_hmac_signature(headers, "/post/raw", int(time.time()) + 10, access_key, secret_key)34 headers['X-Agile-Signature'] = signature35 post_raw_endpoint = 'https://%s/post/raw' % host36 return requests.post(post_raw_endpoint, data=data_stream, headers=headers, verify=False)373839if __name__ == "__main__":40 parser = argparse.ArgumentParser()41 parser.add_argument("--host", default="api.lama.lldns.net")42 parser.add_argument("--local")43 parser.add_argument("--remote")44 parser.add_argument("--access-key")45 parser.add_argument("--secret-key")46 args = parser.parse_args()47 resp = do_post_raw(args.local, args.remote, args.access_key, args.secret_key)48 print (resp.headers)