.wpb_animate_when_almost_visible { opacity: 1; }

Authentication SMS OTP Consent

Published: January 27, 2025

In order to benefit from the SMS OTP Authentication and Consent, service providers must provide the end-user’s mobile number in their API request. The mobile number must be encoded (see below) added to the /authorize authorization request:login_hint. This is a query string type parameter whose value is an encryption of the MSISDN to which we wish to send the SMS.

Creating the login_hint for SMS OTP Authentication

Several rules apply when creating a login_hint:

  • The login_hint consists of the MSISDN and a timestamp, all encrypted in AES-256-CBC, with the Initialization vector in the header.
  • The login_hint is encrypted by the Client and decrypted by the Authorization Server.
  • To be conveyed in the URL, the login_hint is url-encoded.

Example of encoding process

The table below displays the encoding process, so all steps must be followed sequentially:

ElementValue
MSISDN to encode33612345678
UNIX Timestamp in milliseconds (i.e. new Date().getTime();)1453891409214
MSISDN and Timestamp in plain text (timestamp "_" msisdn) (ASCII):1453891409214_33612345678
Generation of a 128-bits Initialization Vector for each encoding:f672e6d89b73dbfb0b97cbe18f89c2ba
openssl rand -hex 16
Derivation of <key> from the <client_secret>:key := bin_2_hexa( sha256( ascii_2_binary(<client_secret>) ) )
command here is:key = crypto.createHash("sha256").update(client_secret).digest();
Login_hint encoded in AES-256-CBC:AES input (ASCII): "1453891409214_33612345678"
AES key (hexa): 617a65727479617a65727479617a65727479617a65727479617a65727479617a
AES IV (hexa): f672e6d89b73dbfb0b97cbe18f89c2ba
AES output (base64): CxaTp04yCdvx8JAqNHdGCK7GGObeGrGBCUvHtcXv1Nk= (BASE64 version "/" and "+")
openssl aes-256-cbc -v -a -K 617a65727479617a65727479617a65727479617a65727479617a65727479617a -iv f672e6d89b73dbfb0b97cbe18f89c2ba -in clear_1.txt -out cypher_base64_1.txt ; more clear_1.txt ; more cypher_base64_1.txt
AES works in blocks of 128b (16hex). The plain text is 256 bits, the encrypted text is 384 bits because of the PKCS#7 padding which adds 128 bits when the size of the data before padding is already a multiple of the block size
Addition of the 128-bit Initialization Vector to the encoded MSISDN to form the login_hintf672e6d89b73dbfb0b97cbe18f89c2ba_CxaTp04yCdvx8JAqNHdGCK7GGObeGrGBCUvHtcXv1Nk=
URL-encoded login_hintf672e6d89b73dbfb0b97cbe18f89c2ba_CxaTp04yCdvx8JAqNHdGCK7GGObeGrGBCUvHtcXv1Nk%3D

Deciphering of the URL-encoded login_hint of the previous example

openssl aes-256-cbc -v -d -a -K 617a65727479617a65727479617a65727479617a65727479617a65727479617a -iv f672e6d89b73dbfb0b97cbe18f89c2ba -in cypher_base64_1.txt -out decypher_1.txt ; more cypher_base64_1.txt ; more decypher_1.txt

Example of JavaScript cipher

var cryptoModule = require('crypto'), //http://nodejs.org/api/crypto.html
loginHint="msisdn_value", // A valoriser Exemple: 33112233445
timestamp = new Date().toISOString(),
     iv = cryptoModule.randomBytes(16),
     key = cryptoModule.createHash("sha256").update("client_Secret").digest(); // Valoriser client_secret : password du partenaire
console.log("key=" + key.toString('hex'));
console.log("iv=" + iv.toString('hex'));
var cryptoCipher = cryptoModule.createCipheriv("aes-256-cbc", key,iv),
     cypheredLoginHint = cryptoCipher.update(timestamp+"_"+loginHint,'utf8', 'base64') + cryptoCipher.final('base64'),
     finalcypheredLoginHint = encodeURIComponent(iv.toString("hex")+"_"+cypheredLoginHint);
console.log("cypheredLoginHint = " + cypheredLoginHint);
console.log("finalcypheredLoginHint = " + finalcypheredLoginHint);
CheckID-API-icon

Match ID France

Cross check your customer information with ours, to mitigate fraud while improving user experience.

Form ID France

Speed up enrollment on a third-party site by automatically populating forms

Decorative icon for the Home Verify API

Home Verify France

Transmit to service providers a digitized (mobile or web) bill from Orange customers as proof of residence