QR Device Registration Example¶
This shows some capabilities of the Extension Engine and how you might implement a QR Device registration. The scripts are based on the following flow:
- User logs in on the website or portal with their credentials
- Once logged in, user selects register device option in the portal
- Website calls the Onegini Token Server on the backchannel endpoint
- The Onegini Token Server triggers the backchannel script for this Identity Provider (
CUSTOM_API_ONE_STEP
) and returns the result to the website - Website generates a QR code based on the response
- User scans this QR code with the mobile app that is not registered yet
- Mobile app calls the Onegini Token Server on the complete endpoint
- The Onegini Token Server triggers the complete script and returns the result to the mobile app
- User is asked to create a new PIN code in the mobile app if the result is successful
Backchannel Script¶
The backchannel script is the first part of QR registration. It is used as a way to interact with the Extension Engine before the actual
user gets involved with their app. You can utilize this script to store data that will be fetched later. In our example, we send a userId
to be stored as well
as the callbackUrl
that is used to notify the caller as soon as the complete script is executed. Below is a sample string that sends a userId
and
callbackUrl
in the requestPayload.
Example request to the backchannel script:¶
{
"data": "{\"userId\":\"exampleUserId\", \"callbackUrl\":\"https://portal.onegini.com/callback\"}"
}
Example Script¶
function execute(requestPayload) {
var userId = JSON.parse(requestPayload).userId;
var callbackUrl = JSON.parse(requestPayload).callbackUrl;
var identifier = java.util.UUID.randomUUID().toString();
// Store any data you need
CACHE.store(identifier, userId, 35); //sets TTL to 35 seconds for this key.
var transactionID = CACHE.fetch(userId);
if (!transactionID) {
transactionID = java.util.UUID.randomUUID().toString();
CACHE.store(userId, transactionID, 300); //Generate transaction for user
CACHE.store(transactionID, callbackUrl, 300); //Set callback URL
}
LOG.info("storing userId: {}", userId);
return {
status: 2000,
responsePayload: JSON.stringify({
uuid: identifier,
transaction: transactionID,
lifetime: 30
})
};
}
The syntax used in the script above is described in more detail in writing scripts section. It utilizes the cache and sets a specific TTL. For more information involving the cache and default TTLs, refer to the cache documentation.
Example response¶
Here is an example response you'd get from the script above. As part of the QR flow, you should parse the identifier and then embed it in the QR code.
{
"data": {
"uuid": "e2048242-085f-4210-93ff-84df1fcd8ce2",
"transaction": "24f8c67e-5957-11eb-ae93-0242ac130002",
"lifetime": 30
},
"status": 2000
}
The data#uuid
field contains the identifier that is meant to be embedded in the QR code and provided to the mobile SDK.
Complete Script¶
The complete script is the second part of QR registration. In this step, the mobile app will allow the user to scan the generated QR code, parse the data
embedded in it, and then send that on to the SDK. In our example, the identifier json is sent with the complete request so it can be used to fetch the userId
and the callbackUrl
that were stored earlier. The json below is a sample of what you would need to send to the SDK. The SDK will automatically escape it when
it sends the request to the Onegini Token Server.
Example String sent to SDK¶
{
"identifier": "e2048242-085f-4210-93ff-84df1fcd8ce2"
}
Example Script¶
function execute(requestPayload) {
var postData = function (url, data) {
var headers = new org.springframework.http.HttpHeaders();
headers.add('Content-Type', 'application/json');
var entity = new org.springframework.http.HttpEntity(data, headers);
REST_TEMPLATE.postForEntity(url, entity, java.lang.String.class);
}
var identifier = requestPayload;
var userId = CACHE.fetch(identifier);
LOG.info("retrieved from cache: {}", userId);
// You may want to delete the entry so the same request cannot be made again
var status = 2000;
if (userId) {
var transactionID = CACHE.fetch(userId);
LOG.info(transactionID);
var callbackUrl = CACHE.fetch(transactionID);
LOG.info(callbackUrl);
LOG.info(JSON.stringify({ "transactionId": transactionID }));
var body = JSON.stringify({ "transactionId": transactionID });
postData(callbackUrl, body);
CACHE.delete(userId);
CACHE.delete(transactionID);
CACHE.delete(identifier);
} else {
status = 5000;
}
return {
status: status,
user: {
id: userId
}
};
}