Excerpt | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Step 1 - Generating the string to be signed
Signature parts | How to generate |
---|---|
Partner ID | As provided by Link Mobility, For example 123. |
HTTP Method | The HTTP Method of the request in upper case. For example "POST", "GET", "PUT" |
URL | The absolute URI of the request, including any query parameters. Lower cased, then URL-encoded. Make sure the special characters of the URL-encoded string are in upper case. For example %3A, not %3a. |
Timestamp | UNIX time, the number of seconds since Epoch UTC (January 01, 1970). For example 1472195737 which corresponds to 2016-08-26T07:15:37+00:00 in ISO-8601. |
Nonce | An reference identifier of your choice, such as a GUID. Max 50 chacters and must be unique per request. |
Content | If there is a payload/body on the request, MD5-hash it first and then base64-encode the result. |
All of the above parts are concatenated into one string. Make sure the resulting string is UTF8 encoded.
Sample string
Code Block |
---|
123POSThttp%3A%2F%2Fpay-core.linkmobility.com%2Fapi%2Ftransactions147219695557bff15b4ecf0yWCdBDtoj/Vb8BE3VqHPtg== |
Figure 1 - create message string
Gliffy | ||||
---|---|---|---|---|
|
Step 2 - Signing the Message
Info |
---|
|
Code Block | ||
---|---|---|
| ||
2FBhBLpuQt9GsXiVI1bMA0dsqEJbEsw4lk3l1G+QLfY= |
Step 3 - Compose Authorization header
You concatenate some of the values from Step 1 and the first 10 characters of the signature from Step 2 and add to the Authorization header with the parts separated by : in the following order
Authorization header parts | How to generate |
---|---|
Partner ID | As provided by Link Mobility, For example 123. |
Signature | The first 10 characters of the HMAC signature created in Step 2. |
Nonce | Your unique reference ID from Step 1. |
Timestamp | The same Unix timestamp from Step 1. |
Code Block | ||
---|---|---|
| ||
Authorization: hmac 123:2FBhBLpuQt:57c08f8dccc59:147223745 |
Figure 2 - HMAC signing and compose Authorization header DIAGRAM
Gliffy | ||||
---|---|---|---|---|
|
Sample C# code for generating the header:
Code Block | ||||
---|---|---|---|---|
| ||||
static void Main() { var secretkey = "<your base-64 encoded secret key here>"; var partnerId = 1; var url = "https://pay-core.linkmobility.com/api/transactions/1/1234"; var method = "GET"; var timestamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds); var nonce = Guid.NewGuid().ToString("N"); var data = partnerId + method + WebUtility.UrlEncode(url.ToLower()) + timestamp + nonce; using (var hmac = new HMACSHA256(Convert.FromBase64String(secretkey))) { var fullHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); var signedHash = Convert.ToBase64String(fullHash).Substring(0, 10); var authHeaderValue = string.Format("hmac \"{0}:{1}:{2}:{3}\"", partnerId, signedHash, nonce, timestamp); Console.WriteLine("Authorization: hmac \"{0}\"", authHeaderValue); } } |
Sample php code for generating hmac header
Code Block | ||||
---|---|---|---|---|
| ||||
<?php $partner_id = '<your LINK Mobility partner id> partner id>'; $secret_key = '<your secret key>'; $secret_key = base64_decode(<your private secret $secret_key); $request_method = strtoupper("GET"); $url = "'https://pay-core.linkmobility.comTODO/api/transactions/$partner_id/<a valid transaction id here>"action'; $url = strtolower($url); $request_bodycontent = ''; $auth_header = getAuthHeader($partner_id, $secret_key, $request_method, $url, $request_content); echo $auth_header; // display the payload/body in the request if any Authorization: header to be included in the request echofunction getAuthHeader($partner_id, $secret_key, $request_method, $url, $request_bodycontent); function getAuthHeader( $partner_id, $secret_key, $request_method, $url, $request_body ) { { $requestUri $request_uri= urlencode(strtolower($url)); $request_timestamp $requestTimeStamp = time(); // current UNIX timestamp $nonce = uniqid(); // string // a unique id if ( !empty($request_bodycontent) ) { $requestContentMd5Hash = md5($request_bodycontent, true); // md5* in raw binary format with $request_body = base64_encode($requestContentMd5Hash); }length of 16 */ } else //{ The string to be signed $message = utf8_encode($partner_id . $request_method . $request_uri$requestContentMd5Hash .= $request_timestampcontent; . $nonce . $request_body); } $hmac_raw = hash_hmac ( 'sha256', $message, $secret$request_key,content true= base64_encode($requestContentMd5Hash); // raw digital output, not hex string $hmac$signatureRawData = base64_encode($hmac_raw); $signature_part = mb_substr ( $hmac, 0, 10, 'UTF-8' ); $auth_header = "Authorization: hmac $partner_id:$signature_part:$nonce:$request_timestamp";$partner_id . $request_method . $requestUri . $requestTimeStamp . $nonce . $request_content ); $hmac_before_base64 = hash_hmac ( 'sha256', $signatureRawData , $secret_key, true ); // not raw digital output return $auth_header; } | ||||
Expand | ||||
| ||||
Code Block | | |||
|
Expand | |||||||
---|---|---|---|---|---|---|---|
| |||||||
| |||||||
Expand | |||||||
| |||||||
|
Expand | ||
---|---|---|
| ||
const crypto = require( 'crypto' ); const { v4: uuidv4 } = require( 'uuid' ); var hmac = generateHmacHeader( '<your-secret-key>' ,12640, 'POST' , 'https://test-paycore.azurewebsites.net/api/pre-transactions?api-version=2.0' , '{"amount": 529, "currency": "NOK", "partnerId": 12640, "paymentProviders": ["Nets", "NetsVipps", "Vipps"]}' ) console.log(hmac); function generateHmacHeader(sharedSecret, partnerId, httpVerb, uri, requestPayload) { var nonce = uuidv4(); var timestamp = Math.floor( new Date().getTime() / 1000); var md5Content = '' ; if (requestPayload) { md5Content = crypto.createHash( 'md5' ).update(requestPayload).digest( "base64" ); } var signatureString = partnerId + httpVerb + encodeURIComponent(uri.toLowerCase()) + timestamp + nonce + md5Content; var hmacSignature = crypto.createHmac( 'SHA256' , new Buffer.from(sharedSecret, 'base64' )) .update(signatureString, 'utf8' ) .digest( 'base64' ); return 'hmac ' + [partnerId, hmacSignature.substring(0, 10), nonce, timestamp].join( ':' ); |
Error codes
Code | Result |
---|---|
401 Hmac timestamp clock-drift too high | The timestamp used to generate the hmac token is too old. It can be max 10 minutes old. |
401 Invalid HMAC | The hmac token in the Authorization header has some invalid content. |
Sample Request
Code Block | ||
---|---|---|
| ||
GET /api/campaigns HTTP/1.1 HOST: pay-core.linkmobility.com Authorization: hmac "1:95onwB16zB:57c44d452af4e:1472482629" Content-Type: application/json |
Sample Response
Code Block |
---|
HTTP/1.1 200 OK Content-Length: 796 Content-Type: application/json; charset=utf-8 ... [{"campaignId":1,"returnUrl":"http://dummy","statusCallbackUrl":"http://dummy","smsStatusCallbackUrl":"http://dummy","smsNotificationOriginator":"2012","smsNotificationText":"Hello","smsReceiptText":"Thank you","shortCode":"2012","currency":"NOK"}, |