Authenticating Requests to the EMS API
Requests to the EMS API are authenticated using two schemes:
- A user token - one can be obtained via special API calls.
- The Hash-Based Message Authentication Code (HMAC) method - used to identify the instrument or software using the API.
The majority of calls require both forms of Authentication in order to authenticate your API call.
Obtaining and Using User tokens
The EMS API uses a user token system to authenticate users. Systems must first identify the user they represent to the API using either Windows Authentication or the users' domain account credentials. Upon successful authentication, the API will return a token code, along with an expiry time of the token. Tokens expire after eight hours, and are tied to the system's API key.
Long running API Calls & User Tokens
User tokens are bound to a combination of API Key and User account, every time you create a User token it will expire any existing tokens for that specific combination of API Key and User account. If you wish to run long jobs with the EMS API you should assign the job it's own service account or manage the User Token generation outside of the job, otherwise you risk breaking the job when a parallel job requests a User Token and overwrites it.
Obtaining a User Token
If you want to obtain a token when you are inside the network:
- Make a call to the V1 POST ems/userTokens/create endpoint using Windows Authentication. If this succeeds, a token code and UTC expiry time will be sent back to you.
- In each subsequent call, Windows Authentication will not be required, but you must include the headers "api-username" and "api-usertoken" in your call. These headers do NOT contribute to the HMAC signature creation, so existing code you have to do that will not need to be changed.
If you want to make a call when you are outside the network:
- You will need to obtain the user's domain credentials. The username must be of the form "Domain\User.Name" (e.g. ExampleDomain\Daniel.Naylor).
- Retrieve the current public key by making a call to the V1 GET ems/userTokens/publicKey endpoint. You will get a Base64 encoded "Modulus" and "Exponent", which are the two components of an RSA generated public key. Do not store this key, it is re-generated periodically when the application is restarted and will become invalid. Encrypt the user's password using this public key.
- Make a call to the V1 POST ems/userTokens/createExternal endpoint with the "Username" and "Password" parameters, passing the domain qualified username, and the encrypted password. If you are passing JSON, any backslashes must be escaped. If this succeeds, a token code and UTC expiry time will be sent back to you.
- Use the token as you would for an internal call.
From this point, internal and external calls are identical. See the UserTokens section on the main help page for more information about these endpoints.
Using the user token
The two headers you need to send will look like the sample ones below. Note that the "api-username" header includes both the domain and the username separated by a backslash:
-
api-username: S2\User.Name
-
api-usertoken: 12345678-abcd-1234-abcd-1234567890ab
If the user does not exist, has not logged onto EMS before, or does not have a current token for the current system API key, the system will reject the request with a 401 (Unauthorised) HTTP status code.
HMAC
Requests to the EMS API are authenticated using the Hash-Based Message Authentication Code (HMAC) method. This allows instruments using the API to be securely authenticated and ensures that requests are not susceptible to tampering. Note: The application of HMAC for both EMS and FLOW are different and should be implemented separately. Application of HMAC for the EMS API involves the following sequence of events:
- Obtain an API Key
- Generate the HMAC signature for your request.
- Add the HMAC signature to your request header
- When the API receives the request, the hash code is recomputed using the "Secret Key" assigned to the relevant "API Key".
- The values of the two hashes (one from the request and one computed by the API) are compared. If they match, then the API Call is authenticated.
Obtaining an API Key
To get an "API Key" and a "Secret Key" an EMS admin will need to add an entry into the EMS Administration page for you. Each API key should only be used by a single user or instrument.
Generate HMAC signature
To generate the HMAC signature for your API call you will need the following information:
- The HTTP Method (i.e. GET, PUT, POST, DELETE).
- The Request Timestamp in UTC format.
- Request URI relative to the base API URI.
- A list of the Form Data and Query string parameters.
- A list of the Files to upload.
Once you have all of the following data we need to combine it together to make our BaseString. For the sake of example we will be making a request to:
POST ems/attachments?EntityType=Experiment&EntityId=12345
Sent at 12:00:00.123 on 14/05/2013, with a file attached called test.txt that has SHA512 hash of aghb9087-- (the actual hash length will be longer): We start with our HTTP Method and append onto it the Request Timestamp in UTC format (YYYY-MM-DD hh:mm:ss.fffZ) using the new line symbol '\n' as separator.
POST\n 2013-05-14 12:00:00.123Z
Now we need to append on the Request URI relative to the base API URI, in this case it would be 'ems/attachments', again we use the new line symbol '\n' as a separator.
POST\n 2013-05-14 12:00:00.123Z\n ems/attachments
Next we need to take our collection of Query string parameters and Form Data (we don't process JSON or XML here), sort them alphabetically by Key and append them to our BaseString. The query string and form body parameters must be encoded using URI Data Encoding. In particular, make sure spaces, ampersands, equals signs and plus signs are URI encoded (not HTML encoded.)
POST\n 2013-05-14 12:00:00.123Z\n ems/attachments\n EntityId=12345&EntityType=Experiment
Finally if we have any file attachments we need to append them using the format: 'Filename=HashOfContent&Filename2=HashOfContent2', again these need to be ordered alphabetically by filename.
POST\n 2013-05-14 12:00:00.123Z\n ems/attachments\n EntityId=12345&EntityType=Experiment\n test.txt=aghb9087--
Now we have our BaseString we need to convert it to all lowercase then hash it with the API Secret Key. Take the API Secret key and hash it using the SHA-512 algorithm, then use this key to hash the BaseString using a HMAC-256 algorithm, this result gives us our HMAC signature.
Add the HMAC Signature to the request header
The "API Key" and computed HMAC signature should be appended to the request headers, using the Authentication key. The two values should be separated by a colon.
Authentication: [API Key]:[HMAC signature]
If the Authentication header is missing or has been generated with an incorrect "API Key" or "Secret Key", the API will respond with a HTTP 401 (Unauthorized) status code and will not execute the request.
The Timestamp used to generate the HMAC signature should also be appended to the request headers, using the Timestamp key. The Timestamp should be in UTC format:
Timestamp: YYYY-MM-DD hh:mm:ss.fffZ YYYY = Year MM = Month DD = Day hh = Hour (24hr format) mm = minutes ss = seconds fff = milliseconds Z = UTC indicator
If the Timestamp header is missing or the request timestamp does not match the server time (within a 5 minute tolerance), the API will respond with a HTTP 401 (Unauthorized) status code and will not execute the request.