When authenticating, make sure all GET/POST operations have correctly added the Authorization header to the HTTP request using a custom "ntc" authentication scheme.
Cervey will provide an Application ID and API Key to each entity requesting access to the Claims API. The Application ID will uniquely identify that entity in each API call. The API Key is a shared secret that should be stored securely, which will allow Cervey to verify that the caller of the API is who they claim to be.
When we receive an API request, we will examine the authentication header and the included hash of several values, which will also be passed in with the request separate from their combined hashed value. We will perform the same hashing process using the values passed in the request and the shared secret (API Key). If the hashed value sent in matches the hashed value we calculate, the API call will be validated.
The authentication header value should be made up of the following values, in order and separated by colons:
ntc 0F4575AB5CDE496E96A2C8CEC4AEFE57C82C007A29974A8E8D4335F70CC140F9:9p+gbTsvF3hbdtySQ5GIUxDQ1pjB3atEIJ35dBpwfpM=:7ca9e83609f74bdcbf3199d6c410fff5:1527025062
string AppID = "0F4575AB5CDE496E96A2C8CEC4AEFE57C82C007A29974A8E8D4335F70CC140F9"; string APIKey = "RsMhYGkrSq9ty7+t2vG3kdcJSLbDbrwn13+ldP6KoXY="; string requestUri = string.Format("{0}{1}", APIBaseAddress, "company"); requestUri = System.Web.HttpUtility.UrlEncode(requestUri.ToLower()); string requestHttpMethod = "GET"; // Calculate UNIX time DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc); TimeSpan timeSpan = DateTime.UtcNow - epochStart; string requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString(); // Create random nonce for each request string nonce = Guid.NewGuid().ToString("N"); // Create signature by concatenating AppID, requestHttpMethod, requestUri, requestTimeStamp, and nonce string signatureRawData = String.Format("{0}{1}{2}{3}{4}", AppID, requestHttpMethod, requestUri, requestTimeStamp, nonce); // Get secret key bytes var secretKeyByteArray = Convert.FromBase64String(APIKey); // Get bytes from signature string data byte[] signature = Encoding.UTF8.GetBytes(signatureRawData); // Use secret key as the key parameter for the HMACSHA256 constructor using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray)) { // Hash the signature using HMACSHA256 byte[] signatureBytes = hmac.ComputeHash(signature); // Convert hashed signature bytes to base64 to send to API end point string requestSignatureBase64String = Convert.ToBase64String(signatureBytes); // The header value consists of colon separated values of AppID, the base64 signature, nonce, and request time stamp AuthenticationHeaderValue headerVal = new AuthenticationHeaderValue( "ntc", string.Format("{0}:{1}:{2}:{3}", AppID, requestSignatureBase64String, nonce, requestTimeStamp)); }
// Postman Pre-request Script /* Pre-requisite ================== 1) Create an Environment in Postman(if you don't already have one) and enable it for your request a) Add APIKey and ClientID variables to the environment with correct values function S4() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); } function GetNonce() { return (S4() + S4() + S4()+ S4() + S4() + S4() + S4()+ S4()).toLowerCase(); } function GetTimeStamp() { var d = new Date(); return Math.round(d.getTime() / 1000); } function getAuthHeader(requestUrl, httpMethod) { var APIKEY = pm.environment.get('APIKey'); var CLIENTID = pm.environment.get('ClientID'); var requestTimeStamp = GetTimeStamp(); var nonce = GetNonce(); requestUrl=encodeURIComponent(requestUrl); var signatureRawData = [CLIENTID, httpMethod, requestUrl.toLowerCase(), requestTimeStamp, nonce].join(""); var key = CryptoJS.enc.Base64.parse(APIKEY); var hash = CryptoJS.HmacSHA256(signatureRawData, key); var hashInBase64 = CryptoJS.enc.Base64.stringify(hash); var header = [CLIENTID, hashInBase64, nonce, requestTimeStamp].join(":"); return "ntc "+ header; } var {Property} = require('postman-collection'); const substitutedUrl = Property.replaceSubstitutions(request.url, pm.variables.toObject()); pm.request.headers.add({key: 'Authorization', value: getAuthHeader(substitutedUrl, request['method']) });
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.UUID; import java.net.http.HttpRequest; import java.net.http.HttpClient; import java.net.URI; import java.net.http.HttpResponse; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.concurrent.TimeUnit; import java.util.Date; public class Main { public static final String BaseUrl = "https://claimsapi.cervey.com"; //-- API credentials need to be updated here private static final String apiKey = ""; // Update this private static final String apiClientID = ""; // Update this // Modify the signature and add the Authorization header to the request public static String addAuthenticationHeader(HttpRequest.Builder requestBuilder, String absoluteUri, String httpMethod) throws Exception { //-- Encodes the URL and ensures it's lowercase to maintain consistent formatting. String encodedURL = URLEncoder.encode(absoluteUri.toLowerCase(), StandardCharsets.UTF_8.toString()); encodedURL = encodedURL.toLowerCase(); //-- Calculates a timestamp based on the current time, starting from January 1, 1970. long requestTimeStamp = TimeUnit.MILLISECONDS.toSeconds(new Date().getTime()); //-- Generates a unique identifier (nonce) for each request to prevent replay attacks. String nonce = UUID.randomUUID().toString().replace("-", ""); //-- Combines key elements into a raw string that will be hashed. String signatureRawData = String.format("%s%s%s%s%s", apiClientID, httpMethod, encodedURL, requestTimeStamp, nonce); //-- Converts the API key from base64 into bytes. byte[] secretKeyByteArray = Base64.getDecoder().decode(apiKey); //-- Hashes the signature data using HMACSHA256 with the secret key. Mac hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyByteArray, "HmacSHA256"); hmac.init(secretKeySpec); //-- Creates the final signature as a base64 string. byte[] signatureBytes = hmac.doFinal(signatureRawData.getBytes(StandardCharsets.UTF_8)); String requestSignatureBase64String = Base64.getEncoder().encodeToString(signatureBytes); //-- Adds the Authorization header with the appID, signature, nonce, and timestamp. String authorizationHeader = String.format("ntc %s:%s:%s:%s", apiClientID, requestSignatureBase64String, nonce, requestTimeStamp); requestBuilder.header("Authorization", authorizationHeader); return authorizationHeader; // Return the auth header so we can print it later } // Send a request to the Company API endpoint public static HttpResponsegetCompany(HttpClient httpClient) throws Exception { String absoluteUri = BaseUrl + "/api/company"; // Example endpoint // Create the request builder HttpRequest.Builder requestBuilder = HttpRequest.newBuilder().uri(URI.create(absoluteUri)).GET(); // Add authentication headers to the request String authHeader = addAuthenticationHeader(requestBuilder, absoluteUri.toLowerCase(), "GET"); // Build the request and send it HttpRequest request = requestBuilder.build(); HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Print the response body System.out.println("Status Code: " + response.statusCode()); System.out.println("Response Body: " + response.body()); // Print the Authorization header System.out.println("Authorization Header: " + authHeader); return response; } public static void main(String[] args) throws Exception { HttpClient httpClient = HttpClient.newHttpClient(); getCompany(httpClient); } }
import base64 import hashlib import hmac import time import uuid import urllib.parse import requests # API credentials need to be updated here api_key = "" # Update this api_client_id = "" # Update this base_url = "https://claimsapi.cervey.com" def add_authentication_header(url, http_method): # URL encode and ensure it's lowercase encoded_url = urllib.parse.quote(url.lower(), safe='').lower() # Calculate timestamp request_timestamp = int(time.time()) # Generate nonce nonce = uuid.uuid4().hex # Combine key elements into raw data string signature_raw_data = f"{api_client_id}{http_method}{encoded_url}{request_timestamp}{nonce}" # Convert API key from base64 to bytes secret_key_byte_array = base64.b64decode(api_key) # Hash the signature data using HMAC-SHA256 with the secret key hmac_obj = hmac.new(secret_key_byte_array, signature_raw_data.encode('utf-8'), hashlib.sha256) request_signature_base64_string = base64.b64encode(hmac_obj.digest()).decode('utf-8') # Create Authorization header authorization_header = f"ntc {api_client_id}:{request_signature_base64_string}:{nonce}:{request_timestamp}" return {"Authorization": authorization_header}, authorization_header # Return header dict and auth header string def get_company(): # Construct the absolute URL absolute_url = f"{base_url}/api/company" # Add authentication header headers, auth_header = add_authentication_header(absolute_url, "GET") # Send GET request response = requests.get(absolute_url, headers=headers) # Print status code and response body print(f"Status Code: {response.status_code}") print(f"Response Body: {response.text}") # Print the Authorization header print(f"Authorization Header: {auth_header}") if __name__ == "__main__": get_company()