Every request is authenticated with an API access token, sent in the X-Miva-API-Authorization header. The token’s settings add IP restrictions, request signing and timestamps, and its permissions decide which functions it can run. For a step-by-step walkthrough, see Create an API token and Make a signed request with HMAC.
Token Security Settings#
Access to the API is determined by an API Access Token. This token is generated in the Miva admin under Users > API Tokens
Within the access token setting, there are 3 additional levels of security:
IP Address Whitelist#
Each access token is restricted to a list of IP addresses you want to have access to make API calls. It accepts a comma separated list of IPs. If you don’t have static IP addresses, you can disable it by using 0.0.0.0/0 which will allow any IP address. You may also need to whitelist the short hand for ipv6 which is: ::/0.
Security Warning
Its highly recommended the IP restriction be used for added security. Only disable this security feature if you don’t have way to get a single or range of IP addresses.
HMAC Signature#
This is an optional but strongly recommended feature to prevent man in the middle attacks on API requests. Miva will generate a signature which you then use by adding it and the message body to an hmac function, where the encryption algorithm is either SHA256 or SHA1. The response then gets passed in the header of the request with the name of “X-Miva-API-Authorization”.
Use SHA256
Sign new integrations with HMAC-SHA256. HMAC-SHA1 is still accepted for older integrations. For a step-by-step walkthrough with PHP, Node.js and Python examples, see Make a signed request with HMAC.
Header Format#
X-Miva-API-Authorization: type <access token>[:<hmac>]
Header Types & Examples#
MIVA-HMAC-SHA256
MIVA-HMAC-SHA1
MIVA (no hmac present)
API Access Token Header with No HMAC signature
POST /mm5/json.mvc HTTP/1.1
Host: support-test-01.coolcommerce.net
Content-Type: application/json
X-Miva-API-Authorization: MIVA 0f90f77b58ca98836eba3d50f526f523
Accept: */*
Content-Length: 629
API Access Token Header with SHA256 signature
POST /mm5/json.mvc HTTP/1.1
Host: support-test-01.coolcommerce.net
Content-Type: application/json
X-Miva-API-Authorization: MIVA-HMAC-SHA256 0f90f77b58ca98836eba3d50f526f523:OkRybggj8ukGviuiwB1u2+ZTS7n4gneyuSybkNdstZI=
Accept: */*
Content-Length: 629
API Access Token Header with SHA1 signature
POST /mm5/json.mvc HTTP/1.1
Host: support-test-01.coolcommerce.net
Content-Type: application/json
X-Miva-API-Authorization: MIVA-HMAC-SHA1 0f90f77b58ca98836eba3d50f526f523:OkRybggj8ukGviuiwB1u2+ZTS7n4gneyuSybkNdstZI=
Accept: */*
Content-Length: 629
Base64 Encoding
It is very important that once the hmac function is run the value needs to be base64 encoded before being passed in the header. Also the signature needs to be base64 decoded before it gets passed into the hmac function.
Steps to Generate HMAC Header#
base64decode signature- Pass
base64decoded signature, algorithm type (sha1orsha256) and JSON request body into your languages HMAC, which function as separate parameters. base64encode result ofhmacfunction and pass in header of each request
HMAC Functions#
Here are hmac functions in some popular scripting languages:
- PHP: hash_hmac
- Ruby: OpenSSL::HMAC
- .Net HMAC Class
- JavaScript (3rd party library) jsSHA
Generate HMAC Header in PHP Example#
protected function generateAuthHeader($data)
{
$key = $this->getSigningKey();
$digest = $this->getOption('signing_key_digest');
if ( !$key )
{
throw ClientException( 'No signing key to sign request' );
} else if ( !isset($this->digests[$digest]) )
{
throw new ClientException( 'Digest %s is invalid. Available digests are %s',
$digest, implode(',', array_keys( $this->digests ) ) );
}
$signature = hash_hmac($this->digests[ $digest ], $data, base64_decode($key), true);
return sprintf('%s %s:%s', $digest, $this->getApiToken(), base64_encode($signature));
}
PHP CURL Example#
<?php
define( 'STORE_CODE', 'dev' );
define( 'API_URL', 'https://localhost/mm5/json.mvc' );
define( 'API_TOKEN', '64d39340a4aaf6e3c752a461f68be2d2' );
define( 'API_SIGNING_KEY', 'NglO1/NYZeYmnID0DrMIjuXqdD3nxBpNLp0FJlfjQbQ' ); // this is a base64 encoded string - copy directly from Miva Admin
define( 'API_SIGNING_DIGEST', 'sha256' ); // sha256, sha1, or null. sha256 is the default setting.
$request = [
'Store_Code' => STORE_CODE,
'Function' => 'ProductList_Load_Query',
'Miva_Request_Timestamp' => time()
];
try
{
$content = json_encode( $request );
$response = sendAPICurlRequest( $content );
}
catch ( Exception $e )
{
die( $e->getMessage() );
}
/**
* Sends an api curl request.
*/
function sendAPICurlRequest( $content )
{
$handle = curl_init( API_URL );
if ( !is_resource( $handle ) ) {
throw new Exception( 'Curl Error: Unable to initialize' );
}
$curlOptions = [
CURLOPT_POST => true,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2
//CURLOPT_SSL_VERIFYPEER => false,
//CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_POSTFIELDS => $content,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
sprintf( 'X-Miva-API-Authorization: %s', generateAuthHeader( API_TOKEN, API_SIGNING_KEY, API_SIGNING_DIGEST, $content ) )
]
];
if ( curl_setopt_array( $handle, $curlOptions ) === false )
{
$error = curl_error( $handle );
$errorno = curl_errno( $handle );
curl_close($handle);
throw new Exception( sprintf( 'Error Setting Curl Options', $error, $errorno ) );
}
$response = curl_exec( $handle );
if ( curl_errno( $handle ) !== 0 )
{
$error = curl_error( $handle );
$errorno = curl_errno( $handle );
curl_close( $handle );
throw new Exception( sprintf( 'HTTP Error: %s Code %d', $error, $errorno ) );
}
curl_close( $handle );
return $response;
}
/**
* Generate the authentication header value
*/
function generateAuthHeader( $apiToken, $signingKey, $digest, $data )
{
if ( !in_array( $digest, ['sha256','sha1'] ) )
{
return sprintf( 'MIVA %s', $apiToken );
}
$signature = hash_hmac( $digest, $data, base64_decode( $signingKey ), true );
if ( $signature === false )
{
throw new Exception( 'Error generating signature' );
}
return sprintf( 'MIVA-HMAC-%s %s:%s', strtoupper( $digest ), $apiToken, base64_encode( $signature ) );
}
Timestamp#
This is an optional value for most functions, and highly recommended security feature to help prevent a replay attack against an API request. When enabled each API request has a max window of execution of 30 seconds from the timestamp passed in the body of the request. To use this feature pass the following parameter in the JSON body:
"Miva_Request_Timestamp" : "1535646272"
The value passed should be a unix timestamp of the time the request was initiated. Miva will then give a 30 second window for that request to be received.
API Integrations
While the timestamp and HMAC signature are optional, both will be required if you have an integration you want listed in the app store.
SSH Authentication#
Miva 10 introduces user level SSH Authentication as an alternate way to connect to the Miva JSON API.
Benefits of using SSH Authentication
- No IP Restrictions - Since authentication is tied to the user, additional reporting is available about who made the request.
- No need to generate a new API token/signature for each store you want to connect.
Important
SSH requests require the Timestamp be passed in each request with a 30 second window. Also, the admin user must not be locked out and the users password must not be expired or set to force to change.
Generate SSH Key#
Miva only supports ssh-rsa format SSH keys. DSA, ed25519, and ECDSA are not supported. Below is an example of how to generate an SSH key:
ssh-keygen -t rsa -m pem
This will generate both a public and private key file on your local computer. The public key file will have a .pub extension and this value should be copied into your Miva user under: Edit Profile -> Manage SSH Authentication
SSH Authentication Header#
Simular to the token/signature authentication outlined above you must also pass a custom authentication header for SSH
X-Miva-API-Authentication: SSH-RSA-SHA2-256 <username>:<signature_bas64>
X-Miva-API-Authentication: SSH-RSA-SHA2-512 <username>:<signature_base64>
Generate SSH Signature#
The SSH Signature required to be passed in the header is generated using the following steps
- Pass SSH private key, algorithm type (
sha256orsha512) and JSON request body into your languageshmacfunction as separate parameters. base64encode result ofhmacfunction and pass in header of each request in the Signature Note: All our our JSON API SDKs support SSH authentication. You point the library to your SSH key an our SDK will generate the required header.
Group & Function Permissions#
In addition to being used for authentication, each access token has Group and Function Level permissions. These permissions will determine which API functions they are allowed to run.
Group Permissions#
Group permissions allow an access token to inherit the permissions assigned to each individual group. These are the same group permissions used to give to Miva Administrator users. To assign group permissions to an access token, select the record from the batch list and a Groups button will display.
Group Functions#
You can also explicitly tie an access token to one or more functions. The full list of API available functions can be found in the left menu. Here you provide whether it is a domain level or store level function and then the function name. You can use Groups and Functions in conjunction with each other to get the correct permissions you need.
Module Functions#
For access to module level functions you can add the function in this format:
Module:MODULE_CODE_HERE:MODULE_FUNCTION_HERE