Introduction
LoQ (PC Login QR) is a feature to identify and authenticate a user on a web-site just with QR-code on login page. User does not have to provide his login, password or any type of one-time passwords.
User's scenario is just to scan a QR-code with his mobile app and to confirm login operation.
At the same time user will be identified with their identifier in the mobile app, authentication will be processed with digital signature process using PC transaction confirmation feature.
How it works you can see at PC Demo page.

Idenitification and Authentication workflow
There are at least 8 components, which participate in user's identification and authentication process with LoQ feature.
As a result, web-application back-end will receive from LoQ components PC User ID and PC Transaction ID of identified and authenticated user.
After this web-application can match PC User ID with user's record in their database and proceed with user’s authorization.
Prerequisites
- LoQ feature must be activated and installed in a customer’s infrastructure (or cloud-based installation can be used)
- Web-application must be linked with PC (web-application users must use PC for transaction confirmations)
Workflow
The workflow is shown on the Figure 1 (it's recommended to enlarge the Figure).
Workflow Participants
| Name | Functions |
|---|---|
| WebApp back-end | WebApp back-end processes users' requests. In this workflow it must request LoQ JS from LoQ Internal component, place it into login page and provide it to a user |
| Web Browser | Web browser on the user's side will process LoQ JS, draw QR-code to login and, after a user will be identified and authenticated, will redirect a user to authorized zone |
| LoQ JS | LoQ JS is a java-script that does following: - request a QR-code and with Session Params from LoQ External with specified interval (by default - every 1 minute) - check with LoQ External if a user was already identified and authenticated with specified interval (by default - every 1 second) - recieve and re-draw QR-code on the login page or make a redirect to WebApp authorization link after a user is identified and authenticated |
| LoQ External | Component to interact with LoQ JS and PC Mobile SDK. Should be placed in DMZ with access from/to Internet |
| LoQ Internal | Component to interact with WebApp back-end and PC Server, produces and processes Session Params during user identification and authorization. Makes a callback to WebApp back-end to pick the PC User ID of identified and authenticated user in the Session. Should be placed in internal network without internet connection |
| PC Server | Component to create and confirm transaction to authenticate a user |
| Mobile App | Calls PC Mobile SDK methods, provides UI for a user on a mobile phone |
| PC Mobile SDK | Processes LoQ workflow on a mobile phone side: - reads QR-value with Session Params - makes a request to LoQ External with specified PC User ID - processes transaction confirmation (digitally signing) to authenticate a user |
Workflow steps (by the schema)
- When
WebApp back-endreceives a request for login page (a new user opens a web session), it callsLoQ Internalfor aLoQ JSand specifies need parameters: PC system_id, login message, url to make a callback when user will be identified and authenticated and url to redirect the Web Browser into authorized zone.
LoQ JSwill contain all of the needed information to interact withLoQ External, draw the QR-code for login and check if a user was already authenticated.
WebApp back-endshould realizecallback endpointwithcallback_urlto receive data about identified and authenticated PC User and PC Transaction ID. Based on this informationWebApp back-endshould authorize a user.WebApp back-endshould realizeredirect endpointwithredirect_url. To this address web browser will be redirected byLoQ JSafter user authentication. Before that callback will be sent tocallback_url.
WebApp back-endembedsLoQ JSinto login page and sends it to user’sWeb browser.- From this step,
LoQ JSstarts to interact withLoQ External, draws and renews QR-code for login and checks if a user was authenticated. - On each request from
LoQ JSLoQ Externalchecks session data, renews QR-code if needed and sendsredirectionin case of user was authenticated. - After QR-code was shown in the
Web browserMobile Appcan scan this QR-code to start identification and authentication process. - QR-code value (decoded value) should be provided to
PC Mobile SDK, after this authentication process can be started:- call
PCLogin.importFromJSON(…) - determine if one of registered PC Users can be used for login (users are registered in the same PC System)
- request Login Transaction to authenticate a user
- call
- Based on the request from
PC Mobile SDKwith user’s identifierLoQ Externalmakes a request toLoQ Internalfor create PC Transaction withPC Server. This transaction must be signed to authenticate a user. - PC Transaction ID will be provided via
LoQ InternalandLoQ ExternaltoPC Mobile SDK. - After this
PC Mobile SDKrequests transaction data and provides them toMobile Appto show to a user. - If a user agrees to login,
Mobile AppwithPC Mobile SDKsigns the transaction. - After PC Transaction was signed and verified,
PC Serversends callback toLoQ Internal. LoQ Internalsends callback toWebApp back-endwith PC User ID and PC Transaction ID in the current session.WebApp back-endshould mark by internal rules that- in the session with specified
session id - user with specified
pc user id - authenticated by signing transaction with specified
pc transaction id
- in the session with specified
- On the next request from
LoQ JSLoQ Externalwill answer thatWeb browsershould be redirected toredirect_urlwithsession idparameter. LoQ JSredirects browser toWebApp back-end’sredirect_url,WebApp back-endreceives fromWeb browsersession id.WebApp back-endchecks which user was identified and authenticated in the session with specifiedsession id(step 13).- If a user was found, then
WebApp back-endauthorizes web session to access to authorized zone. - Optionally,
WebApp back-endcan retrieve all of the information about transaction confirmation (digital signature value, mobile device data, transaction details and so on) fromPC Serverwith specified transaction id.
Integration and API
Get LoQ JS
Get LoQ JS
endpoint: {{loq-internal-url}}/system/loginUser
method: POST
content-type: application/json
Request
{
"systemId" : "{{pc-system-id}}",
"callback" : "{{callback-url}}",
"redirect" : "{{redirect-url}}",
"sessionTimeout" : 6000,
"qrTimeout" : 600,
"size" : 300,
"text": "Please, confirm your login to the best web site",
"textRenderType": "raw",
"qrUrlPrefix": "paycontrol",
"deepLinkPrefix": "paycontrol",
"deepLinkOnly": false,
"pcTransactionAppExtra": "{\"app_callback_deeplink\": \"https://abs.absnet.loc/login_success\"}"
}
Response sample with JS-script and Session ID
{
"jsScript": "[JS will be here (see sample below)]",
"sessionId": "7db47b87-8107-4d25-a967-9210e0d50b20]"
}
Default JS for LoQ
// LoQ JS Script
getQr = function () {
var xhr = new XMLHttpRequest();
var urlLoq = 'https://dev.paycontrol.org/api5/loqr/ext/site/status';
var body = {
sessionId: "1e9a02b9-8827-4df7-a518-923007430872"
};
var loginQR;
var loginDeepLink;
var isRefreshRequired;
makeRequest();
function makeRequest() {
let data = JSON.stringify(body);
let response;
xhr.open('POST', urlLoq);
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.setRequestHeader('Pragma', 'no-cache');
xhr.send(data);
xhr.onload = function (e) {
if (this.status === 200 || this.status === 201) {
response = JSON.parse(e.target.response);
isRefreshRequired = response.isRefreshRequired;
loginQR = response.loginQR;
loginDeepLink = response.loginDeepLink;
checkQR(response);
console.log(response);
} else {
console.log(e.target.onerror);
}
setTimeout(makeRequest, 1000);
}
;
}
function checkQR(response) {
if (response.redirect != null) {
loginQR = null;
document.getElementById('pc_lo_qr').src = "";
var redirectForm = document.createElement('form');
var sessionId = document.createElement('input');
document.body.append(redirectForm);
redirectForm.append(sessionId);
redirectForm.setAttribute('action', response.redirect.url);
redirectForm.setAttribute('method', 'post');
redirectForm.setAttribute('hidden', 'true');
sessionId.setAttribute('name', 'sessionId');
sessionId.setAttribute('id', 'sessionId');
sessionId.setAttribute('type', 'hidden');
sessionId.setAttribute('value', response.redirect.sessionId);
redirectForm.submit();
}
if (response.isRefreshRequired || typeof (loginQR) == undefined) {
loginQR = response.loginQR;
loginDeepLink = response.loginDeepLink;
document.getElementById('pc_lo_qr').src = "data:image/gif;base64," + loginQR;
if (null != loginDeepLink) {
document.getElementById('pc_lo_deeplink').href = loginDeepLink;
}
}
}
};
This request is to generate JS-script with all of the params to work on the web browser side.
| Parameter | Mandatory | Description |
|---|---|---|
| systemId | yes | PC System ID |
| callback | yes | Callback url to provide information about identified and authenticated PC User |
| redirect | yes | Redirect |
| sessionTimeout | yes | Login session life time in seconds. After this time session can not be used to login |
| qrTimeout | yes | QR-code life time. After this time QR-code will be regenerated automatically by LoQ External |
| size | yes | QR-code size in pixels |
| text | no | Login transaction text. This text will be used to create PC Transaction and should be shown to a user in mobile app. If the text not specified then "empty" transaction wil be created. Good practice is to include in the text information about Operation System, Browser version and Login Time. |
| textRenderType | no | Method to render the text in mobile app. Can be raw or markdown. Default value is raw |
| qrUrlPrefix | no | If this value is set, then deep-link with specified proto (prefix) will be encoded into QR-code. It will be useful in case your app can handle deep-links and a user will use qr-scanner to scan a QR (for example, Camera App on iOS). Deep-link in QR will look like [qrUrlPrefix]://loq?login_json=[json to be provided to PC Mobile SDK] |
| deepLinkPrefix | no | If this value is set, then, in addition to QR code, LoQ will generate deep-link to be shown on mobile version of your login page. It means, that your login page can show QR code for desktop version and deep-link for mobile version. A user can tap on the deep-link to start login process (your mobile app should handle deep-links). Deep-link in QR will look like [deepLinkPrefix]://loq?login_json=[json to be provided to PC Mobile SDK] Be noticed, that JS will place QR and deep-link into HTML DOM separately (see default JS). |
| deepLinkOnly | no | If this value is true, then QR-code will be not generated, but deep-link only will be provided. It's useful if you request login from mobile web-browser |
| pcTransactionAppExtra | no | This value will be translated to PC Server's Transaction during login process. And this value will be provided to a mobile app. See Create Transaction Request This value can contain variable %SESSION_ID% in addition to variables, set by PC Server. |
Response will return JS-script that should be embedded into login-page in <script></script> html-tag.
Login-page content
Example JS-code to launch LoQ
// if LoQ JS was embedded successfully
if (typeof getQr === "function") {
getQr();
}
Default LoQ JS tries to find pc_lo_qr object with type img in HTML DOM structure and to insert into src property value of recieved QR-code.
If deepLinkPrefix is set, then Default LoQ JS tries to find pc_lo_deeplink object with type a and insert deep-link into href property.
To launch the interaction process between LoQ JS and LoQ External login-page must execute function with default name getQr (see example).
LoQ JS can be tuned or replaced (if required) during LoQ installation process. In this case, functions' or objects' names can be different.
Callback receiver requirements
Callback content
endpoint: {{callback_url}}
method: POST
content-type: application/json
{
"pc_callback":{
"loqr_callback":{
"sessionId":"25552734-a388-4f30-8517-2b67598f2f75",
"pcUserId":"c1d656e9-481b-4244-ade1-f36ec10eff25",
"transactionId":"bf6c447a-0f82-4bd3-a49f-0c460bea4fcc"
},
"type":"loqr_callback",
"result":{
"error_message":"Success",
"error_code":0
},
"version":3
}
}
After a user will be identified and authenticated LoQ Internal will send callback to WebApp back-end to callback_url, specified in Get LoQ JS request.
| Parameter | Mandatory | Description |
|---|---|---|
| pc_callback.type | yes | Value must be loqr_callback |
| pc_callback.loqr_callback | yes | Data about identified and authenticated user |
| pc_callback.loqr_callback.sessionId | yes | LoQ session id used to authenticate a user |
| pc_callback.loqr_callback.pcUserId | yes | Authenticated PC User ID |
| pc_callback.loqr_callback.transactionId | yes | PC Transaction ID which was signed by authenticated user. |
| pc_callback.result | yes | Error description |
| pc_callback.version | yes | Callback version |
Redirect receiver requirements
Default script to make a redirect
// clear QR-code value
document.getElementById('pc_lo_qr').src = "";
// create html-form
var redirectForm = document.createElement('form');
document.body.append(redirectForm);
redirectForm.setAttribute('action', response.redirect.url);
redirectForm.setAttribute('method', 'post');
redirectForm.setAttribute('hidden', 'true');
// add input with name sessionId
var sessionId = document.createElement('input');
sessionId.setAttribute('name', 'sessionId');
sessionId.setAttribute('id', 'sessionId');
sessionId.setAttribute('type', 'hidden');
// set sessionId value to recevied from LoQ External value
sessionId.setAttribute('value', response.redirect.sessionId);
redirectForm.append(sessionId);
// submit the form to redirect
redirectForm.submit();
After a LoQ JS will receive information about user was authenticated, it will redirect Web browser to redirect_url specified in Get LoQ JS request.
Default LoQ redirection method is js-script that embeds html-form into HTML DOM model and submits them.
Before this script clears QR-code value.
So, if you are using default redirection method, redirect receiver on WebApp back-end side should process request with application/x-www-form-urlencoded content-type.
JS-script to proceed the redirection can be tuned or replaced if needed during LoQ installation process.
Mobile App Requirements
Mobile App should realize LoQ process as shown on the schema.
Login process from mobile app point of view are managed with PCLogin class.
The sample algorithm of logging in with QR-code (or deep-link) is the following:
- Scan QR code (or handle deep-link) and extract json containing all required data
- Call
importFromJson(String, GetLoginDataCallback)to constructPCLoginobject. Constructed object will be returned as parameter ofsuccess()method. - Call
suggestUsers()on constructed object to get keys which can be used to log in - After choosing a key call
requestLoginTransaction(PCUser, GetLoginTransactionCallback)with a selectedPCUserfrom one of returned bysuggestUsers() - After
PCLogin.GetLoginTransactionCallback.success(PCTransaction)is invoked, you may show transaction data in the app. Note, that thePCTransaction.getTransactionText()can either return null or text of transaction. Do not try to sign this transaction manually, instead call eitherconfirm(PCGeneralCallback)to finish logging in ordecline(PCGeneralCallback)to cancel login operation.
You can find more detailed information in PC Mobile SDK.
At the same time reference PC Mobile Application can be used.
Infrastructure integration
Components interaction
LoQ contains of two parts: LoQ External and LoQ internal.
Roles of this parts you can find in the workflow description.
Login workflow participants interaction diagram you can find on Figure 2.
Server component supply options
LoQ server components are supplied as Java application (jar-file) and instruments to run as service (linux- or windows-based).
LoQ uses Redis cache server to store data about active sessions. Redis should be installed to be accessible from LoQ Internal and LoQ External components.
Typical machine components
A typical machine (or a container) consists of the following installed components:
| Component | Description |
|---|---|
| Operating system | Linux-based |
| Application server operation environment | Java 8/11 |
All the LoQ components are launched automatically with the operating system. No manual settings for start/shutdown is required.
If neither a physical nor virtual servers are supplied, the OS preparation is carried out by the customer. Preparation includes:
- Installation of the operating system;
- Proper configuration of DNS records;
- Installation of the Java Runtime Environment;
- Preparing TLS certificates (if necessary).
The following alternative components can be used:
| Component | Description |
|---|---|
| Operating system | Microsoft Windows |
| Application server operation environment | Java 8/11 |
Resiliency and scaling
Resiliency and scaling options are equals to PC Server components.
Installation and startup
Under docker
At first you need to deploy and grant access to same Redis database for Internal and External LoQR components.
For start under docker you need to modify to change entrypoint script file for openjdk.
Dockerfile
FROM openjdk:17
COPY ./docker-entrypoint.sh /
WORKDIR /opt/loqr/
ENTRYPOINT ["/docker-entrypoint.sh"]
Entrypoint script executes java with last (in alphanumeric order) jar-file in directory in workdir and name of a configuration file.
docker-entrypoint.sh
#!/bin/sh
JARFILE=$(ls *.jar | tail -1)
java -jar $JARFILE application.yml
There is templates of application.yml files. You need to specify the next values:
- loqr.pc.url — PCS API endpoint.
- loqr.url — address of Internal LoQR component. Uses for callback from PC when login transaction is confirmed.
- loqr.urlExternal — external address for External LoQR component. It will added to JavaScript for pulling session status and updates of QR code.
- spring.redis — address of Redis database.
- loqrExternal.loqr — internal address of Internal LoQR component. Uses for call by Internal LoQR for login transaction creation.
- loqrExternal.url — external address for External LoQR component. This address will be added to QR, and will be used for communication mobile SDK with External LoQR module.
- loqrExternal.logoQRPath — optional. Path to image file for adding to QR as a logo.
application.yml for Internal LoQR component.
server:
port: 8098
address: 0.0.0.0
loqr:
parametrs:
qr:
width: 120
height: 120
typeImg: "gif"
pc:
url: "http://pc:8080/pc-api/"
url: "http://loqrint:8098"
urlExternal: "https://example.com/loqr/ext"
timeoutInSecond:
QR: 120
session: 600
spring:
redis:
host: redis
port: 6379
database: 1
jedis:
pool:
min-idle: 2
max-active: 500
max-idle: 50
max-wait: 30
#logging:
# level:
# tech.paycon: DEBUG
application.yml for External LoQR component
server:
port: 8099
address: 0.0.0.0
loqrExternal:
loqr: "http://loqrint:8098"
logoQRPath: "pc_logo.png"
url: "https://example.com/loqr/ext"
timeoutInSecond:
QR: 120
session: 600
spring:
redis:
host: redis
port: 6379
database: 1
lettuce:
pool:
min-idle: 8
# logging:
# level:
# tech.paycon: DEBUG
docker-compose.yml
version: '3.7'
services:
loqrint:
container_name: "loqrint"
volumes:
- "/opt/pc/loqr/int/:/opt/loqr:Z"
restart: unless-stopped
build: images/loqr
depends_on:
- redis
loqrext:
container_name: "loqrext"
volumes:
- "/opt/pc/loqr/ext/:/opt/loqr:Z"
restart: unless-stopped
build: images/loqr
depends_on:
- redis

