Control APIs are RESTful APIs that leverage HTTP’s well-defined and consistent message envelope. RESTful architectures are designed for resource passing by placing method information in the method, scoping information in the path, client information in the headers, and the representation of the resource in the body.
The elements of the HTTP request are:
- Method
- URI path and parameters
- Header
- Representation of resource in the body or document
The elements of the HTTP responses are:
- Response code
- Header
- Representation of resource in the body or document
HTTP Requests
URI Path and Parameters
The general form of the URL for requests is:
https://host:port/${api-name}/${version}/${resource-name}/${sub-level}/${resourceId}?${params}
where:
- host and port - define the host and port where the application lives (port is optional)
- api-name - API name (for example, purge-api)
- version - the API version for this feature (e.g., v1)
- resource-name - name of the resource requested (e.g., request)
- sub-level - optional level to further specify the requested resource
- resourceId - resource identifier, if applicable for the method
- params - additional parameters for pagination, search, authentication, etc.
Unless otherwise noted, arguments are case-sensitive.
API Version
The REST APIs are subject to version control. The version number of an API appears in its URI. For example, this URI structure requests version 1 of an API:
https://host:port/api-name/v1/resource-names
Notes:
- The API version number is an integer with v prefix, such as v1 or v2.
- The API version is independent of the release number.
- The API version may or may not change with a new release. The API version number changes only when updates to the API break the API contract, requiring changes in the code that uses the API. A change to the API does not necessarily require a change to the API version number.
- For multiple API versions, each version will ideally support at least two API versions: the latest API version and the previous API version.
Media Type
Some REST API requests accept resources, and most REST API responses return resources. These resources can be in either JSON or XML format; the default is JSON. The media type of the request resource must be specified in the Content-Type header (application/json or application/xml). The media type of the response resource is specified in the URI (responseType=json or responseType=xml) or in the Accept header (application/json or application/xml).
Parameters
URI parameters can be for pagination, search, authentication, and/or specific parameters for an API resource.
Authentication
The Edgio REST APIs use a combination of symmetric key cryptography and Hashed Message Authentication Code (HMAC) for message authentication and user identification.
To secure all calls to the API, an HMAC digest signature is applied to each request by using the following authentication headers:
- X-LLNW-Security-Principal – name of user performing the request. Services look up shared keys by username to authenticate a message. Since shared keys are stored on a per-user basis, to impersonate another user, an attacker would have to know both the username and the shared key for that user.
- X-LLNW-Security-Timestamp – request time in milliseconds. Prevents replay attacks. If the timestamp is more than X seconds old (usually 300), the message expires, and an error code is returned. Note: System clock skew minimization is an important consideration for message expiration.
- X-LLNW-Security-Token – MAC hash-generated with the user’s shared key. It is calculated based on data that is sent to the server. This token is generated twice: once by the client and once by the server to compare with the one passed by the client. If the token provided by the client matches the token generated by the server, the message is authentic. Shared key is a large unique key created for use with the “HmacSHA256” MAC algorithm. Control maintains a unique and enciphered shared key for every user in the system. It is stored in HEX format and should be decoded to ASCII before usage (see code samples below). Users may access or regenerate this key at any time by using tools in Control under My Settings > Edit My Profile.
- X-LLNW-Security-Token is formed by applying a MAC digest for the “data string” (for example,
REQUEST_METHOD + URL + QUERY_STRING [if present] + TIMESTAMP + REQUEST_BODY
(if present)).
- X-LLNW-Security-Token is formed by applying a MAC digest for the “data string” (for example,
Java Sample Code for HMAC Generation
java
1import java.io.IOException;2import java.io.UnsupportedEncodingException;3import java.security.InvalidKeyException;4import java.security.NoSuchAlgorithmException;5import javax.crypto.Mac;6import javax.crypto.spec.SecretKeySpec;7import org.apache.commons.codec.DecoderException;8import org.apache.commons.codec.binary.Hex;9public class HMACGenerationExample {10 private static String HMAC_ALGORITHM = "HmacSHA256";11 public static void main(String[] args) throws IOException,12 InterruptedException, InvalidKeyException, NoSuchAlgorithmException,13 DecoderException {14 String sharedKey = "your_key";15 //sharedKey is what you see in Control on Edit My Profile page16 String url = "<api base url>";17 /* base url example: "https://control.llnw.com/18 traffic-reporting-api/v2" */19 String queryString = "<query string parameters>";20 /*queryString example: "shortname=bulkget&service=http&21 reportDuration=day&startDate=2012-01-01" */22 String postData = "{param1: 123, param2: 456}";23 byte[] rawHmac = generateMac(sharedKey, "GET", url, queryString,24 postData);25 String hmac = new String(Hex.encodeHex(rawHmac));26 System.out.println(hmac);27 }28 private static byte[] generateMac(String sharedKey, String httpMethod,29 String url, String queryString,30 String postBody)31 throws NoSuchAlgorithmException, InvalidKeyException,32 IllegalStateException, UnsupportedEncodingException,33 DecoderException {34 byte[] decodedSharedKey = Hex.decodeHex(sharedKey.toCharArray());35 long timestamp = System.currentTimeMillis();36 String dataString;37 if (queryString == null) {38 dataString = httpMethod.toUpperCase() + url + timestamp;39 } else {40 dataString = httpMethod.toUpperCase() + url + queryString +41 timestamp;42 }4344 if (postBody != null) {45 dataString = dataString + postBody;46 }47 SecretKeySpec keySpec = new SecretKeySpec(decodedSharedKey,48 HMAC_ALGORITHM);49 Mac mac = Mac.getInstance(HMAC_ALGORITHM);50 mac.reset();51 mac.init(keySpec);52 return mac.doFinal(dataString.getBytes("UTF-8"));53 }54}
Python Sample Code for HMAC Generation
python
1import hashlib2import hmac3import time4try: import simplejson as json5except ImportError: import json6class HMACSample:7 def generateSecurityToken(self, url, httpMethod, apiKey, queryParameters=None, postData=None):8 timestamp = str(int(round(time.time()*1000)))9 datastring = httpMethod + url10 if queryParameters != None : datastring += queryParameters11 datastring += timestamp12 if postData != None : datastring += postData13 token = hmac.new(apiKey.decode('hex'), msg=datastring, digestmod=hashlib.sha256).hexdigest()14 return token15if __name__ == '__main__':16 apiEndpoint = "<api base url>"17 #example: "https://control.llnw.com/traffic-reporting-api/v2"1819 #what you see in Control on Edit My Profile page#20 apiKey = "your_key";2122 queryParameters = "<query string parameters>"23 #example: "shortname=bulkget&service=http&reportDuration=day&startDate=2012-01-01"24 postData = "{param1: 123, param2: 456}"25 tool = HMACSample()26 hmac = tool.generateSecurityToken(url=apiEndpoint, httpMethod="GET", queryParameters=queryParameters, postData=postData, apiKey=apiKey)27 print json.dumps(hmac, indent=4)
Request Header
The Accept
HTTP Header
can specify the response format. The default is JSON
.Accept=application/json
The Content-Type
HTTP Header
can specify the format of the request body. This header is required for all resources that require a request body.Content-Type=json
The HTTP
X-LLNW-Security-Token
, X-LLNW-Security-Principal
, X-LLNW-Security-Timestamp
headers form the authentication envelope.X-LLNW-Security-Token=<mac>
X-LLNW-Security-Principal=<username>
X-LLNW-Security-Timestamp=<now in milliseconds>
Representation of Resource in the Body or Document
Some APIs expect a payload of information in JSON format in the request body for
PUT
or POST
methods. This payload is known as the body or document of the request and is a representation of the resource for the API. The format must specified with the Content-Type
header.HTTPS Responses
A response header, returned for each API request, contains:
- one of the HTTP Response Status Codes
- the returned media type in the
Content-Type
header (for example,application/json;charset=UTF-8
)
The response body, returned for each API request, contains either:
- a status entity or
- a response entity (representation of the resource)
The format of the response body is determined by the
responseType
parameter or Accept HTTP Header
in the request.HTTP Response Status Codes
HTTP Status Code | Name | Description |
---|---|---|
5xx | Server-Side Error | Any server-side error |
200 | OK | Request was processed as expected. |
201 | Created | Request created an entity. |
202 | Accepted | Request was processed as expected. |
304 | Not Modified | The requested resource has not been modified, and the client’s cached representation is still valid. |
400 | Bad Request | The request could not be understood due to bad syntax. |
401 | Unauthorized | Client is not authenticated or does not have sufficient permission to perform this request. Similar to 403 Forbidden but specifically for use when authentication is possible but has failed or has not yet been provided. |
403 | Forbidden | The request was a legal request, but the server is refusing to respond to it. Unlike a 401 Unauthorized response, authenticating will make no difference. |
404 | Not found | The requested resource could not be found at this location (URI), but may be available again in the future. Subsequent requests by the client are permissible. |