This article provides additional information about the internal workings of the API Server which will be relevant if you are writing your own API Sever client. For normal users, using the standard libraries, functions, form fields and workflow tasks described in the rest of the documentation, this information can be ignored.
Tokens
Checking an API Key and credentials is a potentially expensive operation. To speed things up the first such successful request to the API Server will be responded to with a token that can be used in subsequent requests. The token has a short lifespan and is only accepted from the IP address to which it was issued to limit the potential for abuse. It may be used in place of the API Key and credentials whilst it remains current. Checking a token is a very fast operation and a token should always be used when available.
When a token expires, you will receive an HTTP 401 status response (you will receive this status whether or not credentials are required). You should then repeat the request with the API Key and any credentials to get another token.
Tokens are issued and submitted using the x-api-token header of the HTTP response and request respectively.
Security Protocol
The precise requirements for access to any particular API will be defined in the security configuration in iCM. We assume that an API Key and credentials are required for the following example.
The first access to the API must provide the x-api-key header and the HTTP basic authentication headers. The API Server will use the Key to determine if your client IP address is permitted and will validate the credentials. It will then check that the user identified by the credentials is in the group permitted by the Key. If these checks are passed then the API is called with the authenticated credentials which it may use as required. At the same time a token is created and the API Server caches the entire set of security data (key, credentials, client IP, token and expiry time) in memory. The token is returned with the response. Any failure to verify your permission will result in an 401 HTTP status.
The next request should use the token as this is much more efficient. When you supply a token you should not supply any other security details. The token is checked to see if it exists and that it has not yet expired. The client IP address is also checked to see that it exactly matches the address to which the token was issued. If everything checks out then the request continues as if the original API Key and credentials were supplied. If there is a problem then you will receive a 401 HTTP status and this will usually indicate the the token has expired. Simply repeat the request with the API Key and credentials and get a new token. If this request fails then it indicates that there is a genuine problem with your API Key, IP address or credentials.
Client Pseudo-code
Send a request to the API Server with an API Key and return the response and the security token. Pass the previously returned token back in to each call to Send, or pass null if this is the first call. Likewise, the credentials should be null if not required.
A more sophisticated client would be an object that was initialised with the API Key and that recycled the current token automatically. This example is deliberately simplistic to highlight the method rather than the implementation.
Send(Url url, string body, string apikey, string token, string credentials)
{
request = new HTTPRequest(url);
if(token == null)
{
request.headers.add("X-Api-Key", apikey);
}
else
{
request.headers.add("X-Api-Token", token);
}
if(credentials != null)
{
// This assumes that credentials is properly
// formatted and Base64 encoded
request.headers.add("authorization", "Basic " + credentials);
}
request.body = body;
response = request.send();
if(response.status == 401)
{
if(token == null)
// We have failed to obtain a token with our
// current apikey, credentials and client IP
throw "failed to authorise";
else
// Perhaps our token has expired, null it
// and attempt to obtain a replacement
return Send(url, body, apikey, null, credential);
}
else if(response.status == 200)
{
token = response.headers.get("X-Api-Token");
result = response.body;
return [token, response];
}
else
{
throw "Failed with status " + response.status;
}
}