Mobile-to-Web Cross Login Using a QR Code

Subhajit Dutta
3 min readSep 8, 2022

--

Cross Login System

What does it mean?

You can say it is two-factor authentication. You may have seen a similar example in popular chat applications like Whatsapp.

In this process, if you are already logged in to a mobile app (Android / iOS), and a user wants to use their session to authenticate another app (Say Web app), they can do it seamlessly without again following the same login process.

How to develop a similar system?

Prerequisites

  1. An active web-socket connection (Here we will use Pusher)
  2. Mobile App (react Native)
  3. Web App (NextJs)
  4. Backend Server (ExpressJS)

Overall Process

  1. The initial page of your web application makes a request to the server to generate a QR code.

2. Server generates a QR code with an encoded unique value and sends a response to the web app. In this case, it will be the name of the channel. Channel name will be created using a combination of a unique token and timestamp. A new QR code will be generated every 10 secs.

3. The web app downloads the generated QR code and displays it on the web page.

4. The web app connects to the messaging channel (Got from step 2) and waits for a message. The message will be sent by the Android app later.

5. On the mobile app, a user logs in with their phone number and otp. As a result of the login, the Android app receives a user-token, which uniquely identifies the user and his/her session.

6. The user using the same mobile app scans the QR code from the web page screen, receives the messaging channel, and sends the user-token into the channel.

7. The web application receives the message which contains the user-token. The token can be used for the API calls made in the web app as it now will carry the user’s identity.

Let’s Code

WebApp: Request for QR Code, show it and listen to the messaging channel

Server: Generate QR Code on the server

const generateQR = async (req, res) => {
const token = crypto.randomBytes(64).toString('hex');
let channel_data = new Date().getDate() + "-" + new Date().getMonth() + "-" + new Date().getMinutes()
let channel_data_hash = crypto.createHash('md5').update(channel_data+"||"+token).digest("hex");

return res.status(200).json({
success: true,
msg: "QR DATA Created",
data: {
channel: channel_data_hash
}
})
}

Android: Scan QR Code and Send Auth Token to server

Server: Accepts the auth-token and sends it to the web app via WebSocket

let channel = req.body.channel
let token = req.body.token
let user_id = req.body.user_id
try {
let resp = await pusher.trigger(channel, "login-event", {
token,
user_id
});
return res.status(200).json({
success: true,
msg: "",
data: resp
})
} catch (e) {
console.log(e)
}
return res.status(200).json({
success: true,
msg: "Token Triggered",
data: {}
})

Web App: Receives the auth-token via WebSocket, and validates it.

const channel = pusher.subscribe('private-' + res.channel);
channel.bind('login-event', function (data) {
handleLogin(data)
});
const handleLogin = async (data)=>{
const token = data.token
const user_id = data.user_id
try {
let res = await axios.post(apis({}).VERIFY_TOKEN.url, {token, user_id});
await Router.replace('/profile')
return res.data.data
} catch (e) {
console.error(e)
}
return null;
}

THE USER IS LOGGED IN !!!

Store received jwt token using HttpOnly server-side cookie. For every subsequent secure API calls include them using withCredentials:true / credentials:’include’. And on the server extract the cookie and validate the token.

--

--