HMAC Signing of API Requests
 

The below describes the procedure of accessing HMAC protected REST APIs. 

In general our REST APIs require authorization via an OAuth 2.0 "access_token". However, some APIs (currently only the /files/ API) can be accessed also with "HMAC" signed request URLs. Using the HMAC option over OAuth-based access is advantageous whenever the resource owner likes to grant access to a specific method or resource to a third-party (e.g.: providing a download link to a specific file watermarked with a specific tag just for a certain time period). Sharing the resource-owner's OAuth token is not an option because it would grant the receiver full permissions under the scopes associated with the token. Therefore the better approach is to use HMAC signed API URLs to share access to a specific resource with third-parties. HMAC-signed URLs can be one-time and grant access to only specifically the API call pre-signed (authorized) by the resource owner.

Below is a brief about the steps involved in making use of HMAC-based signing of API requests:

  1. Our APIs are protected by various scopes like "mediahub", "autograph", "me", etc. Certain APIs are accessible only when possessing the relevant scopes (this is also the "scope" parameter in the OAuth client credentials flow above). HMAC-based signing follows the scope idea in that it uses application credentials for creating the signature and the signature "inherits" all scopes of the signing application.
  2. The resource owner hence needs to create an application with sufficient scopes as needed for the desired API call(s). He/She will be provided with a "client_id" and "client_secret" in return. 
  3. The resource owner can then HMAC sign and share with his/her users pre-signed API URLs to access certain REST resources.
  4. The Xvid API endpoints verify the signature of all HMAC signed URLs by looking up the corresponding "client_secret" shared with the resource owner and grant access to the requested resource only if the signature could be successfully verified.


Creating a HMAC signed URL

You need to have created an Application in the web app and obtained corresponding "client_id" and "client_secret". These credentials are used to construct the HMAC signed URLs. The following parameters are associated with HMAC signed URLs:

  • client_id : The Application client_id
  • expiry_time : Expiry time, in seconds, after which the signed URL shall be invalidated. The default is 180 seconds.
  • multi_use ( Optional) : true or false. Specifies whether the signed URL can be used multiple times or is invalidated after the first use.

Example

We assume the resource owner has created an Application with client_id "cb379184054d2011389f5a38". He now likes to sign an AutoGraphed file download request, which is:

https://api.xvid.com/v1/files/intern/downloads/?file_id=5463c3882fab72b097d57dee&autograph_tag=ghtcde&redirect=true

Note that for unique autographed downloads the autograph tag must be provided as a query parameter (if the "autograph_tag" query param is not provided, the master copy will be downloaded, which is not unique!). Further, we use the "redirect=true" query parameter, which ensures that the download will start once a user clicks on the signed link in a browser. This way the signed link can be directly displayed as an anchor href on a website or e-mailed to the end-user.

To prevent the end-user from modifying any of the query parameters (in particular the "autograph_tag" parameter!), the entire URL must be protected by a cryptographic signature. For this, we first append the above requst URL with an expiry_timeclient_id and multi_use query parameter and then sign the entire URL string with HMAC using the application client_secret as the signing key. The calculated signature is finally also appended to the URL as signature query parameter.


The below Python script shows how to perform the URL signing as an example:

Prepare HMAC Signed URL
#!/usr/bin/env python

import time
import base64
import urllib
import hmac
import hashlib

# Client Id and Client Secret of Subscribers Application
client_id = "cb379184054d2011389f5a38"
client_secret = "Vl13zLKt5d3U5ENG12/NCd7qnqhqPhWosSQF9feZPJZWjIiXW2YVY62TOKX0MQzR"
# URL to be signed to provide access to Users 
api_base_url = "https://api.xvid.com"
url = "/v1/files/intern/downloads/?file_id=5463c3882fab72b097d57dee&autograph_tag=ghtcde&redirect=true"
validity_in_sec = 30*60    # Expiry time of URL
expires = (int(time.time()) + validity_in_sec) 
multiuse = False
 
# Append URL parameters 
if multiuse == True:
    url = url + "&multi_use=true"
url_params = "&client_id=" + urllib.quote_plus(client_id) + "&expiry_time=" + str(expires)
url = url + url_params

# Sign the URL
key = base64.b64decode(client_secret)
hashed = hmac.new(key, url, hashlib.sha1)
# Prepare the signed URL by adding signature at the end 
url = api_base_url + url + "&signature=" + hashed.hexdigest()
print url


  • No labels