Keyri Firebase QR Login Integration - Session Extension
Incorporating Keyri QR login into your Firebase-based authentication system with
session extension involves sending the user's uid
, emailVerified
,
isAnonymous
, providerData
, and stsTokenManager
strings, booleans, and
objects from your mobile app to your web app via the Keyri mobile SDK and web
Widget. On the mobile side, just load these items (as an object) as the payload
into the Keyri method you're using in your app. On the web side, extract these
items from the payload that the Widget outputs and set them into the IndexedDB.
The Firebase client SDK you have already installed on your web app takes care of
the rest automatically. The following example code walks through how to do this
with a vanilla Webpack-based web app and a Flutter mobile app.
Usage notes:
-
You must first have a Keyri account with a service registered under the domain name on which you will be showing the login QR code
-
Your user must already be registered in your Firebase auth system
-
Your user must already be logged in on your mobile app (the five items listed above must be available and valid for a logged-in session)
Web
The following video walks you through the entire web app integration process:
Source code for an example web app can be found here: https://github.com/Keyri-Co/keyri-firebase-example-web (opens in a new tab).
The live demo is here: https://example-keyri-auth.web.app (opens in a new tab)
Example HTML web page below. First, simply add the Keyri Widget iFrame
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Keyri Firebase Auth Demo</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="keyriQR">
<iframe
src="./KeyriQR.html?Environment=dev&Origin=example-keyri-auth.web.app"
id="keyriQR"
frameborder="0"
height="300"
width="300"
scrolling="no"
style="border: solid 5px white"
></iframe>
</div>
</body>
</html>
Example JS:
import './styles.css';
import { hideLoginError, showLoginState, showLoginForm, showApp } from './ui';
import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
// Replace these with your Firebase config values
const firebaseConfig = {
apiKey: 'AIzaSyCSdJ7cDqtGsxLsTL22FU0s8WYnCyS-43E',
authDomain: 'example-keyri-auth.firebaseapp.com',
projectId: 'example-keyri-auth',
storageBucket: 'example-keyri-auth.appspot.com',
messagingSenderId: '723969996728',
appId: '1:723969996728:web:ce0cb6f546c51edeac014d',
measurementId: 'G-636DMTXSHJ',
};
const firebaseApp = initializeApp(firebaseConfig);
// Monitor auth state
const monitorAuthState = async () => {
onAuthStateChanged(auth, (user) => {
if (user) {
showApp();
showLoginState(user);
hideLoginError();
} else {
showLoginForm();
lblAuthState.innerHTML = `You're not logged in.`;
}
});
};
// IndexedDB storage function
window.dbMaker = async () => {
return new Promise((resolve, reject) => {
const openRequest = indexedDB.open('firebaseLocalStorageDb');
openRequest.onerror = (event) => {
// handle error
console.log('error', event);
};
openRequest.onupgradeneeded = (event) => {
const db = event.target.result;
};
let db;
openRequest.onsuccess = (event) => {
db = event.target.result;
resolve(event.target.result);
};
});
};
//Keyri event listener
window.onmessage = async (eventData) => {
if (eventData.data.keyri && !eventData.data.error) {
let info = JSON.parse(eventData.data.data);
// Transform the payload into the format expected by Firebase
let obj = {
fbase_key: `firebase:authUser:${firebaseConfig.apiKey}:[DEFAULT]`,
value: {
uid: info.uid,
emailVerified: info.emailVerified,
isAnonymous: info.isAnonymous,
providerData: info.providerData,
stsTokenManager: {
refreshToken: info.refresh_token,
accessToken: info.access_token,
expirationTime: info.expirationTimestamp,
},
},
};
// Store the transformed payload in the indexedDB
let db = await window.dbMaker();
const transaction = db.transaction('firebaseLocalStorage', 'readwrite');
const store = transaction.objectStore('firebaseLocalStorage');
store.put(obj);
}
};
const auth = getAuth(firebaseApp);
monitorAuthState();
That should be it for a very basic implementation that includes both Firebase's built-in email/password auth option and Keyri's QR code login method. In your HTML file, be sure to include the proper divs to hold the Keyri QR code and the login form.
Mobile (Flutter Example)
The following video walks you through the mobile app integration process to enable QR login:
This Flutter example shows how to extract the user's uid
, emailVerified
,
isAnonymous
, providerData
, and stsTokenManager
strings/booleans/objects
provided by Firebase in your app and send it to the web Widget via the Keyri
SDK. Be sure to visit the appropriate mobile SDK documentation
for more information about how to install the relevant Keyri SDK for your mobile
app.
try {
final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
password: password,
);
final time = DateTime.now();
final expTime = time.add(Duration(hours: 1));
final token = {
‘refreshToken’: credential.refreshToken,
‘accessToken’: credential.accessToken,
‘expirationTime’: expTime
};
final json = {
‘uid’: credential.uid,
‘emailVerified’: credential.emailVerified,
‘isAnonymous’: credential.isAnonymous,
‘providerData’: credential.providerData,
‘stsTokenManager’: token
};
final payload = json.toString();
await keyri
.easyKeyriAuth(payload, credential.emailAddress)
.then((authResult) => _onAuthResult(authResult))
.catchError((error, stackTrace) => _onError(error));
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}