Getting Started

  1. Sign up at www.thumbsignin.com
  2. Create an app by providing app name, description and logo
  3. You will obtain Application ID and Secret Key that could be used to integrate ThumbSignIn features into your website.

Website Integration

Front End Integration

The ThumbSignIn Registration and Authentication Widgets are used to generate the passwordless authentication GUI for the website. The GUI will consist of the QR code that will be used for registration and authentication respectively.

  1. Add the widget file to project

    Integrating the ThumbSignIn Passwordless integration capabilities on your website frontend requires you to embed a piece of Javascript code in your HTML. Add the 'thumbsign_widget.js in the 'head' section.

    Before the user can authenticate with your website using passwordless authentication, he must register the device he will be using to authenticate with your website.

    <head><script src='https://thumbsignin.com/thumbsign_widget.js'></script></head>
  2. Build the Configuration of the widget

    Specify the actionUrl and statusUrl for the widget to be created. You can also edit the default display names shown on the widget if required

    note: jQuery is optional, it's just used to call 'addConfig' once document 'ready' is Fired, You can implement the same via plain JS as in Sample Code

    /* * CONFIG NAME:'REGISTER_CONFIG' provide an unique config name * ACTION URL :'/tsAuth/register' * STATU URL :'/txnStatus/' */ $( document ).ready(function() { thumbSignIn.addConfig('REGISTER_CONFIG', { actionUrl: "/tsAuth/register", statusUrl: "/txnStatus/" }); });
  3. Initialize the widget

    Now you have to Initialize the widget with a unique name, configuration and Rendering container element (mention the DOM element ID )

    /* * ID :'tsRegister' provide an unique widget ID * CONFIG :'REGISTER_CONFIG' Configuration to be Loaded * CONTAINER :'widgetContainer' ID of the container element */ $( document ).ready(function() { //... //... thumbSignIn.init({ id:'tsRegister', config: 'REGISTER_CONFIG', container: 'widgetContainer' }) //... });
  4. Render the widget

    Once the widget is initialized, you will be able to render it anytime, by calling the open() function over its id

    <body> <button onclick=”tsRegister.open()>Register with Thumbsignin</button> </body>

Sample Register widget

<html> <head> <script src='https://thumbsignin.com/thumbsign_widget.js'></script> </head> <body> <button id="btn">Register with Thumbsignin</button> <button id="close">Close</button> <div id="widgetContainer"></div> <script> (function() { thumbSignIn.addConfig('REGISTER_CONFIG', { actionUrl: "/tsAuth/register", statusUrl: "/txnStatus/" }); thumbSignIn.init({ id:'tsRegister', config: 'REGISTER_CONFIG', container: 'widgetContainer' }).then(function(){ //Add on click events $('#btn').click(function(){ tsRegister.open() }); $('#close').click(function(){ tsRegister.close() }); }) })(); </script> </body> </html>

Widget API

FunctionDescription
openRenders the widget in the container and initiates call for QR code
closeUnmounts the widget from the container and terminates any call processing
registerEventUsed to add callback listeners for the events
refreshMakes a new QR code fetch call
terminateTransactionForcefully expires the current QR code

Event Listeners

Once the widget has been initialized, you can add call back listeners for the events raised in the widget

/* * On successful Registration this redirects to '/sucessPage' * CALL_BACK_SCOPE: holds the 'this' scope of callback (optional) */ thumbSignIn.init({ id:'tsRegister', config: 'REGISTER_CONFIG', container: 'widgetContainer' }).then(function(){ //... tsRegister.registerEvent('SUCCESS', function (response) { window.location.hash = ''; window.location.pathname = "/sucessPage"; }, <CALL_BACK_SCOPE>); //(optional param) })
StatusDescription
INITIATEDFired when the QR code is rendered initially
PENDINGFired post rendering of QR code
ERRORFired when an error raises in module/widget initialization
SUCCESSFired when the QR code is scanned successfully
FAILUREFired when the QR code is scanning fails or cancelled
FETCH_DATA_ERRORFired when the network call fails

Modules

The widget allows developers to add prebuilt and custom modules to scale up the functionality. This shows the sample code of 'tsModal' (prebuilt module)being added to the widget.

/* * 'require' - takes an array of modules that are to be loaded in the widget. */ thumbSignIn.init({ id:'tsRegister', config: 'REGISTER_CONFIG', require: [ 'tsModal' ], // Require the modules that are needed, // by default 'sms' and 'logo' modules are added container: 'widgetContainer' })
  1. SMS Module (prebuilt)

    This is build up to provide SMS functionality for users to get the App link from the App store and Play store.

    /* * param_1: "sms" , the name of the module * Param_2: "config" holds the module constants , * "getElem" should return object with 'elem'(DOM) template and 'style' * Param_3: function callback with 'dom' (compiled template) and config */ thumbSignIn.addModule('sms', { config: { 'smsContent': "", 'smsTitle': "Or get link via SMS" }, getElem: function (config, url) { return { elem: `<div class="tsmodal-footer"> <p class="more-info more-info2" >${config.sms.smsTitle}</p> <div class="more-info"><div class="d-box"> <p id="sms_result" class="more-info"></p> <div class="db-b"> <input type="text" placeholder="123 456 7890" id="phone" maxlength="10"> <img class="d-arrow-b" src="${url}/styles/img/icons-8-sent-filled.png"/> </div> </div></div> </div>`, style: `.more-info{margin:0 auto;max-width:248px} .db-b img.d-arrow-b{position:absolute;right:50px;padding:10px 5px;cursor:pointer}` } } }, function (dom, config) { /* * "this" holds the widget scope, from where you can get the the DOM * "dom" param has the module dom element that has been compiled from * the above template * "config" param holds the widget config in which "sms"(module-name) holds * the module specific config created above * ( ex : smsContent accessed via "config.sms.smsContent" ) */ this.DOM.find("#module-wrapper").append(dom); })
  2. Logo Module (prebuilt)

    This is build up to provide logo banner in the UI for links to Play store and App store.

    /* * param_1: "logo" , the name of the module * Param_2: "config" holds the module constants , * "getElem" should return object with 'elem'(DOM) template and 'style' * Param_3: function callback with 'dom' (compiled template) and config */ thumbSignIn.addModule('logo', { config: { 'appIcon': '/styles/img/icon.png', 'playStoreIcon': '/styles/img/playstore.png', 'playStoreURL': 'https://play.google.com/store/apps/details?id=com.pramati.thumbsignin.app', 'appStoreIcon': '/styles/img/appstore.png', 'appStoreURL': 'https://itunes.apple.com/us/app/thumbsignin/id1122364132' }, getElem: function (config, url) { return { elem: `<div class="ts-logo-wrapper"> <p> Don’t have the app yet? <span id="get_link_by_sms"> Get it now</span> </p> <div style="display: flex;"> <p class="icons"> <img src="${url}${config.logo.appIcon}" height="30px" width="30px"/> <a target="_blank" href="${config.logo.appStoreURL}"> <img src="${url}${config.logo.appStoreIcon}" height="30px" width="90px" style="padding-left:10px;"/> </a> <a target="_blank" href="${config.logo.playStoreURL}"> <img src="${url}${config.logo.playStoreIcon}" height="30px" width="90px" style="padding-left:10px;"/> </a> </p> </div> </div>` style: `.ts-logo-wrapper span{font-weight:500;font-family:Montserrat-Bold;color:#19b2e6} .ts-logo-wrapper p{font-family:Montserrat-Medium;font-size:12px;color:#1a1a39}` } } }, function (dom, config) { /* * "this" holds the widget scope, from where you canget the the DOM. * "dom" param has the module dom element that has been compiled from * the above template * "config" param holds the widget config in which "logo"(module-name) holds * the module specific config created above * ( ex : playStoreURL accessed via "config.logo.playStoreURL" ) */ this.DOM.find("#module-wrapper").append(dom); })
  3. Modal Module (prebuilt)

    This is build up to provide the widget in a popup modal.note: This module requires 'bootstrap.css' file.

    /* * param_1: "tsModal" , the name of the module * Param_2: "config" holds the module constants , * "getElem" should return object with 'elem'(DOM) template and 'style' * Param_3: function callback with 'dom' (compiled template) and config */ thumbSignIn.addModule('tsModal', { config: { 'modalTitle': 'Scan the QR Code', }, getElem: function (config, url) { return { elem: `<button id="tsModalBtn">Open Modal</button> <div id="tsModal" class="modal"> <div class="modal-content"> <h4 class="text-center">${config.tsModal.modalTitle}</h4> <span class="close">&times;</span> <div class="modal-content-wrapper"></div> </div> </div>`, style: `#tsModal{display:none;position:fixed;z-index:1000; left:0;top:0;width:100%;height:100%; overflow:hidden;background-color:rgba(0,0,0,.4)} #tsModal .modal-content{background-color:#fefefe;margin:10% auto; padding:20px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23); border:1px solid #888;width:450px} #tsModal .close{color:#aaa;float:right;font-size:28px;font-weight:700} #tsModal .close:focus, #tsModal .close:hover{color:#000;text-decoration:none;cursor:pointer}` } } }, function (dom, config) { /* * "this" holds the widget scope, from where you canget the the DOM. * "dom" param has the module dom element that has been compiled from * the above template * "config" param holds the widget config in which "tsModal"(module-name) holds * the module specific config created above * ( ex : modalTitle accessed via "config.tsModal.modalTitle" ) */ var widgetObj = this; $('body').append(dom); var modal = $('#tsModal'); modal.find('.modal-content-wrapper').empty().append(this.DOM.detach()); $("#tsModalBtn").click(function () { modal.show(); widgetObj.open(); }); $("#tsModal .close").click(function () { widgetObj.close(); modal.hide(); }); window.onclick = function (event) { if (event.target == modal[0]) { widgetObj.close(); modal.hide(); } } })

Backend Integration

The ThumbSignIn Strong Authentication server needs to notify your server of the status of registration and authentication requests. To receive these notifications, you need to expose a few web URLs on your server which will be called by ThumbSignIn server for status notifications. The following table details the URLs you need to expose and how to handle the callbacks.

URLDescriptionAuthorization
GET /tsAuth/registerCalled by the widget to check the status of a transaction.HMac signed request
GET /tsAuth/registerCalled by the widget to check the status of a transaction.HMac signed request
GET /tsAuth/authenticateCalled by the widget to get the QR code for authenticating a user.HMac signed request
GET /tsAuth/txnStatus/{id}Called by the widget to check the status of a transaction with the specified '/:id'.HMac signed request
GET https://api.thumbsignin.com/ts/secure/devices/{userId}Provides the list of the registered devices for that user.HMac signed request
GET https://api.thumbsignin.com/ts/secure/deregister/{userId}/devices/{deviceId}Send message on successful deregistration of the device.HMac signed request

SaaS REST API

The Thumbsignin server located at https://api.thumbsignin.com exposes the following REST endpoints

GET/ts/secure/register

HEADER

user-agent: "%Your user agent%"

Query String

userId: "%Username or such unique id of the user%"

RESPONSE

transactionId: Provides the transaction ID

status: Which is used for getting status of transaction status.This field can have one of the values following values 'PENDING / COMPLETED_SUCCESSFUL / COMPLETED_FAILURE / INITIATED'.

failureReason: This will contain a text value which describes the reason for transaction failure.This field can have one of the values following values 'ALREADY_REGISTERED / TIMEOUT/ NO_SUITABLE_AUTHENTICATOR / DECLINED / TECHNICAL_REASON'

expireInSeconds: The number of seconds before the transaction expires.

SAMPLE RESPONSE
{ "transactionId":"7e8eeb82d86c549c6d3c56e6d5046f07ea7b98df88aed424", "status":"PENDING", "failureReason":"", "expireInSeconds":89 }

GET/ts/secure/authenticate

HEADER

user-agent: "%Your user agent%"

RESPONSE

transactionId:Provides the transaction ID

status:Which is used for getting status of transaction status.This field can have one of the values following values 'PENDING / COMPLETED_SUCCESSFUL / COMPLETED_FAILURE / INITIATED'.

failureReason: This will contain a text value which describes the reason for transaction failure.This field can have one of the values following values 'ALREADY_REGISTERED / TIMEOUT/ NO_SUITABLE_AUTHENTICATOR / DECLINED / TECHNICAL_REASON'

qrImage: Image data of the QR code. This will be used with desktop browsers only.

deepLinkUrl: Deep linking URL. This will be used with mobile browsers only.

expireInSeconds: The number of seconds before the transaction expires.

SAMPLE RESPONSE
{ "transactionId":"7e8eeb82d86c549c6d3c56e6d5046f07ea7b98df88aed424", "status":"PENDING", "failureReason":"", "qrImage":"iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AQAAAACgl2eQAAADu0lEQVR42r2ZUY4kKQxE4SJw/1vMUeAiMH7PtPpntD+rdHepqpQZJVkQEQ6c7f7335/2/wGrtX73Xq3H6/Q15uqntblG51YJYN8bd8eYfHJzitpndG7VAFbfe4tpUdSJ97m5mK8ywI2KorgxorAocVr03qWAFUsT2zOjVOqcJ1btRK1lgNgRKmuT7dl3DQre8bq/u/kxAGbuf//9svpjAAqNku6KxblHDY15WK79q+6PAah1KpmgyUTDM0AXDsWlWQLYr7R4uxAlVDvlEGWfIsCJytKzBmuzg61hYnEJCe0SQNwJ04j9mTA2qotPi5W3twQAOw+GgYfi4zMJG1uFmZYAuM5+YSL4N3dDtlI3GfU9IL+jnnRUrWuN/EGrASxsk0WxnQV1Za/cCUMrAsBPbCNk0r1hp7exxA9LAAglGXNYqLgYgYMtW1yaNYDr4shSdDs18Ta6TWaXAMIs5As1AWTJYpWQbuBvCQDHbMQJdCPK5ppV0twLADLlRyfNOs9IYyOAlgAgyMr/adphjS5LxdddA4Cp8V2p5i2IYq0NIy0AQNXYITpakNW10tfYrWFT+x7A1rBdOjoaarQVSjRolABcl2ccMqVT7JRHE8IUAK6Zzp4iU0g7+5n5oaEUADj1sECRq8w2ZL6RWatJ2gpA00Ew0yVXLlcMWdnUKgADmcqSNnoeCyk0LfWWANDtyuwdixXfgzb9Rb102u8B0TZanoA5iaHftJHmbKAIoExpYfYSz8Y5qSDs9BJA5htbu0MBNGzo6RhsDYCRwMj5wJqZePNczODi1ADMt1ulyB3Ohg6KhoflEoAjImx0Pg8z+5n8tmZeA3i5zgMYHR0bi/t4ehHgZyqQ7exKWwvGWmcJ4MWZY7jLg/ACuRwU9BKA7fOIYHNYKadmXWO/JQAdi4TXiJiMCfjwMNBSvN8DkifujDKWvjZ6Kq4BXPvGdX7oANFfpHT2mjUALQPTnK6M38y8NvsaAEM6wyVIFkpDvZk6ew2AnUHBdNZGymiMrgQ4sCoAmGeOEc92ymRE/cTeDQ8gBQCSHU806GaZsFLASaQSAKE/x9iO89fI2CuPdxHAOdFTrEkrDx45Y3biXQDglq385hy9vfC3Vx7MCwBW45hM1Xoo9kDctPMSANH2DUV+njK8Cn/C//cAtXtSqSefAc4caiLpXQNY7yGX4aY5MfHdCV4dAJWabmb2V9zsZvopAzgQMPO/gHEdmOSwqALAKNuhzHpDxKmWXk8pAbgzhDw06xTV5yxPxzWA7x/r/wUjLonekDJ0kAAAAABJRU5ErkJggg==", "deepLinkUrl":"https://ccfp.test-app.link/NoPapjn1NG", "expireInSeconds":89 }

GET/ts/secure/txn-status/:id

PARAM

'transaction id' has to be passed for ':/id'

Query String

cancelled: (Optional). This is value is using for cancelling the transaction,
we need to pass ‘true’ to cancel the transaction.

RESPONSE

transactionId: Provides the transaction ID

status: Which is used for getting status of transaction status.This field can have one of the values following values 'PENDING / COMPLETED_SUCCESSFUL / COMPLETED_FAILURE / INITIATED'.

failureReason: This will contain a text value which describes the reason for transaction failure.This field can have one of the values following values 'ALREADY_REGISTERED / TIMEOUT/ NO_SUITABLE_AUTHENTICATOR / DECLINED / TECHNICAL_REASON'

expireInSeconds: The number of seconds before the transaction expires.

SAMPLE RESPONSE
{ "transactionId":"7e8eeb82d86c549c6d3c56e6d5046f07ea7b98df88aed424", "status":"PENDING", "failureReason":"", "expireInSeconds":89 }

It is important to note that all calls to the ThumbSignIn SaaS API must be HMac signed using the application id and the secret key. The secret key should be downloaded from the app dashboard and stored on your server. This will be used to sign the requests made from your server to the ThumbSignIn SaaS server.

Response Status

StatusDescription
PENDINGTransaction created and waiting for user action
COMPLETED_SUCCESSFULTransaction completed successful
COMPLETED_FAILURETransaction failed
INITIATEDStarted user action like scanned QR code 'failureReason': This will contain text value which describe reason of transaction failure, this field can have values listed below
ALREADY_REGISTEREDUser has already registered device for this application,
will happen when the user tries to enable the same device again
NOT_REGISTEREDUser tries to login without registering device
TIMEOUTTransaction timed out without user’s action
NO_SUITABLE_AUTHENTICATORThis will happen in events like user didn’t add fingerprints and not enabled pin/pattern locking
DECLINEDUser click on cancel from ThumbSignin App
TECHNICAL_REASONThis is expected when some technical issue happen in the event of transaction processing
qrImage: Image data of the QR code, this will be displaying only desktop
deepLinkUrl: Will get deep linking URL, this will be available in mobile only
expireInSeconds: The transaction will expire after this much seconds

Node Js sample integration

We provide a helper javascript module called ‘HmacSigner’. Download the 'HmacSigner' module.

import axios from 'axios'; import HmacSigner from '../hmac/sign'; let timer = 180, giveProperResponse = false; const tsServer = "https://api.thumbsignin.com"; const tsServerPath = tsServer + "/ts/secure"; // Insert your application Id and Secret key below const tsCredential = { accessKeyId: "<<Your Application Id>>", secretKey: "<<Your Secret Key>>", }; // Handle GET requests to register and Authenticate router.get('/tsAuth/:action(register|authenticate)', (req, res) => { let session = req.session; let action = req.params.action; // If trying to register when the user is not logged in if (action === 'register' && !session.loginInfo) { res.status(401).json({status: "401", message: "Unauthorized"}); return } let request = { method: 'get', headers: {} }; // Handle a registration request // Get the userrnamr from a previously svaed login session if (action === 'register') { request.url = tsServerPath + '/register?userId=' + session.loginInfo.username; } else { let queryString = session.loginInfo && session.loginInfo.username ? '? userId=' + session.loginInfo.username : ''; request.url = tsServerPath + '/authenticate' + queryString; } // Sign the request first HmacSigner.sign(request, tsCredential); // And then send it to api.thumbsignin.com axios(request).then((response) => { res.status(200).json(response.data) }).catch((error) => { res.status(401).json({ "status": "SERVER_ERROR", "message": error.toString() }); }); }); // If authentication is successful, alter the session to log the user in function loginAndSendSuccess(req, res, data) { let request = { method: 'get', url: tsServerPath + '/getUser/' + data.transactionId, headers: {} }; HmacSigner.sign(request, tsCredential); axios(request).then((response) => { Account.findOne({username: response.data.userId}, (err, account) => { if (err || !account) { res.status(401).json({ status: "INTERNAL_ERROR", "message": err? err :"Unable to login" }); } else { // ALTER SESSION if (!account.fingerprint) { account.fingerprint =true; account.save() } let session = req.session; session.loginInfo = account.sessionInfo(); data.redirectUrl = "/"; res.status(200).json(data); } }) }).catch((error) => { res.status(401).json({ status: "SERVER_ERROR", "message": error.toString(), }) }); } // Handle GET request for checking transaction status router.get('/txnStatus/:id', (req, res) => { let q = req.query.cancelled?"?cancelled=true" :''; let request = { method: 'get', url: tsServerPath + '/txn-status/' + req.params.id + q, headers: {} }; HmacSigner.sign(request, tsCredential); axios(request).then((response) => { if (response.data.status === 'COMPLETED_SUCCESSFUL') { loginAndSendSuccess(req, res, response.data) } else { res.status(200).json(response.data) } }).catch((error) => { res.status(401).json({ status: "SERVER_ERROR", message: error.toString() }) }); });