One-Time Password
Authenticate users and transactions with OTP and 2FA.
Accessing accounts and performing transactions requires strong user authentication. In the context of customers, it is strong customer authentication (SCA) that is required and often mandated. One-Time Passwords (OTP), along with Two-Factor Authentication (2FA), provide a means to verify that a person is who they claim to be.
Ways to use One-Time Password
The Melrose Labs One-Time Password service provides the means to process One-Time Passwords using one of two ways. OTPs are generated by the service, sent to users and verified by the service; or are generated by an application on the user's device (e.g. Google Authenticator) and verified by the service.
Sending OTPs to Users
Sending One-Time Passwords to users can be done with a REST call to our OTP API, and delivered via SMS text message, voice call or email.
When using the Melrose Labs One-Time Password service, we don't let you know the actual One-Time Password that has been sent to your user, therefore preventing potential leakage of this critical information at the source.
TOTP Service: OTP and Google Authenticator
Time-base One-Time Passwords: Users can quickly be enrolled with the One-Time Password service and use the Google Authenticator mobile app on their mobile to generate OTPs. The user provides the OTP that was generated on their mobile and the service then verifies this.
Use of this method may be preferable in some scenarios.
Integrate with the One-Time Password service
Integrate OTP into your application using our OTP API. For simple integration, use one OTP API call to send an OTP to a user and another API call to verify what the user provided.
Sending OTP codes and verifying code from user
To send an OTP, you specify the message content and the recipient. You can also specify the complexity of the OTP (e.g. length, digits-only, letters-only or letters and digits) and its expiry. Delivery of the OTP will take place in a few seconds when using SMS text, email or voice call.
SIM-Swap Detection: For OTP delivery to UK mobiles via SMS or voice call, a check can be performed to confirm that the user account is not the victim of SIM-swapping.
TOTP Service: Verify code from user when using Google Authenticator
Enroll user with service: Make REST API call to add user to service. Provide user with enrolment link for them to scan QR code with Google Authenticator.
When user then performs login or transaction, ask them for TOTP code from Google Authenticator. Make a REST API call to the OTP service and provide the TOTP code from the user and the user's OTP service user ID. The service will then verify if the provided code is valid for that user at that time.
REST API
The Melrose Labs One-Time Password service is available using our REST Identity API.
Create Domain
Create an authentication domain for users.
Request:
curl https://api.melroselabs.com/identity/otp/domain/ \
--header 'x-api-key: [API_KEY]'
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183"}
Request:
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api.melroselabs.com/identity/otp/domain/',
'headers': {
'x-api-key': '[API_KEY]'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body); // response is of type application/json
});
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183"}
Request:
import requests
import json
url = "https://api.melroselabs.com/identity/otp/domain/"
headers = {
'x-api-key': '[API_KEY]'
}
response = requests.request("POST", url, headers=headers)
# response is of type application/json
print(response.text.encode('utf8'))
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183"}
Request:
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.melroselabs.com/identity/otp/domain/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => array(
"x-api-key: [API_KEY]" )
));
$response = curl_exec($curl);
curl_close($curl);
echo $response; // response is of type application/json
?>
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183"}
Create user
Create a user within an authentication domain.
return_secret
set to true
will cause the generated secret to be returned. This should then be given to the user to add into Google Authenticator and enrolment will be assumed to have been completed. When set to false
, or omitted, the secret will not be returned and instead an enrolment URL will be returned. The enrolment URL allows users to add the secret themselves to Google Authenticator.
set_secret
is used to specify the secret to be used, rather than the service generate a secret.
We recommend the use of anonymised user IDs (user_id
) with the service, rather than email addresses or similar that third parties can easily identify individuals with. Examples use email address to clearly illustrate purpose of field.
Request:
curl https://api.melroselabs.com/identity/otp/user/ \
--header 'x-api-key: [API_KEY]' --header 'Content-Type: application/json' \
--data-raw '{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "return_secret": true}'
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "secret": "QIATV7YPGLQKDDIC", "type": "totp", "interval": 30}
Request:
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api.melroselabs.com/identity/otp/user/',
'headers': {
'x-api-key': '[API_KEY]',
'Content-Type': 'application/json'
},
body: JSON.stringify({"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "return_secret": true})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body); // response is of type application/json
});
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "secret": "QIATV7YPGLQKDDIC", "type": "totp", "interval": 30}
Request:
import requests
import json
url = "https://api.melroselabs.com/identity/otp/user/"
payload = {
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "return_secret": true}
}
headers = {
'x-api-key': '[API_KEY]',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = json.dumps(payload))
# response is of type application/json
print(response.text.encode('utf8'))
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "secret": "QIATV7YPGLQKDDIC", "type": "totp", "interval": 30}
Request:
<?php
$data = {"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "return_secret": true}
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.melroselabs.com/identity/otp/user/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => array(
"x-api-key: [API_KEY]",
"Content-Type: application/json"
)
));
$response = curl_exec($curl);
curl_close($curl);
echo $response; // response is of type application/json
?>
Response:
{"domain": "cabcc674-a328-432d-b925-0d5c3e79a183", "user_id": "john.grant@melroselabs.com", "secret": "QIATV7YPGLQKDDIC", "type": "totp", "interval": 30}
Identity Check
Check time-based code provided by user is correct.
Request:
curl https://api.melroselabs.com/identity/otp/totp/ \
--header 'x-api-key: [API_KEY]' --header 'Content-Type: application/json' \
--data-raw '{"user_id": "john.grant@melroselabs.com", "code": "704471", "domain": "f5af5a70-e34c-40ad-8e6b-9e2cc883364f"}'
Response:
{"verified": true}
Request:
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api.melroselabs.com/identity/otp/totp/',
'headers': {
'x-api-key': '[API_KEY]',
'Content-Type': 'application/json'
},
body: JSON.stringify({"user_id": "john.grant@melroselabs.com", "code": "704471", "domain": "f5af5a70-e34c-40ad-8e6b-9e2cc883364f"})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body); // response is of type application/json
});
Response:
{"verified": true}
Request:
import requests
import json
url = "https://api.melroselabs.com/identity/otp/totp/"
payload = {
{"user_id": "john.grant@melroselabs.com", "code": "704471", "domain": "f5af5a70-e34c-40ad-8e6b-9e2cc883364f"}
}
headers = {
'x-api-key': '[API_KEY]',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = json.dumps(payload))
# response is of type application/json
print(response.text.encode('utf8'))
Response:
{"verified": true}
Request:
<?php
$data = {"user_id": "john.grant@melroselabs.com", "code": "704471", "domain": "f5af5a70-e34c-40ad-8e6b-9e2cc883364f"}
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.melroselabs.com/identity/otp/totp/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => array(
"x-api-key: [API_KEY]",
"Content-Type: application/json"
)
));
$response = curl_exec($curl);
curl_close($curl);
echo $response; // response is of type application/json
?>
Response:
{"verified": true}
Get your API Key now and start using the One-Time Password service REST API
SIGN-UP | LOGIN TO GET API KEYPricing
Contact us for Melrose Labs One-Time Password pricing.
Data Retention and Data Privacy
Data retention and data privacy policies ensure that data is handled securely and in accordance with GDPR. Mobile telephone numbers and message content are kept encrypted at rest and in motion whenever possible. Account-level policies ensure that messages are erased in line with your organisation's data retention policy.
Service snapshot
- Part of strong customer authentication
- Simple OTP service API
- OTP delivery to device, or device generated OTP (TOTP)
- OTP delivered via SMS, voice or email
- Enhanced OTP with SIM-swapping fraud check