Products
Use cases
Resources & Case studies
- Products
- Use cases
- Resources & Case studies
The aim of this tutorial is to lay out the steps for integrating TypingDNA Verify 2FA on a basic Node.js website that is using Keycloak as the Identity and Access management solution.
In this tutorial we will build a sample web application that is using TypingDNA Verify 2FA. The user will first introduce the username and password that will be verified by Keycloak, and that information will then be used by TypingDNA Verify for a second factor of authentication. We will cover all technologies that are needed to run a simple demo on a local machine.
In order to create a working example of TypingDNA Verify 2FA, the following actions need to be taken:
Create an account on typingdna.com. The Verify 2FA dashboard will provide you with the clientID, secret and applicationID.
Setup ngrok. Ngrok creates a public url that will link to your localhost environment. For security purposes, TypingDNA Verify 2FA will only run on a public url. Ngrok can be downloaded from the following link: https://ngrok.com/.
We will be setting up Keycloak on a localhost using a Windows machine.
Make sure you have OpenJDK 1.8 or newer installed.
First step is to download and extract keycloak-15.0.2.zip from the Keycloak website.
Navigate to the new extracted folder, then to start Keycloak run the following command.
bin/standalone.bat
Once Keycloak has booted up, open http://localhost:8080/auth, then fill in the form with your preferred username and password.
Now that Keycloak has been set up to run on our localhost we will start designing our application.
Let’s create a simple website application. We will be using a lot of the information from the tutorial on TypingDNA Verify from Tech with Tim so for more detailed information please check out his video tutorial.
Create a basic node.js application using the following command:
npx express-generator website
Delete the bin, public and routes folders.
Delete the 3 jade files inside the views folder.
Edit the app.js such that it will have the following code:
const express = require('express');
const path = require('path');
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
From the package.json file remove the following dependencies: morgan, http-errors and cookie-parser.
"dependencies": {
"debug": "~2.6.9",
"express": "~4.16.1",
"jade": "~1.11.0"
}
Next change directory to the website directory and run npm install
.
Next run npm install pug typingdna-verify-client keycloak-js
We will start by creating a router:
const router = express.Router();
And we will also add:
app.use("/", router);
app.listen(3000, () => {
console.log ("Listening on port 3000");
});
Change
app.set('view engine', 'jade');
To
app.set('view engine', 'pug');
And out app.js file will look like this:
const express = require('express');
const path = require('path');
const app = express();
const router = express.Router();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use("/", router);
app.listen(3000, () => {
console.log ("Listening on port 3000");
});
Create the file verify.pug in the views folder.
We will populate the following code in the verify.pug file:
html
head
body
h1 TypingDNA Verify 2FA
And in the app.js we will add.
router.get("/verify", (req,res) =>{
res.render("verify");
});
Next navigate to the folder where ngrok was downloaded and run the following command:
Ngrok.exe http 3000
And you will see a window similar to this:
Now start your web application using:
node .\app.js
And access the link from your ngrok window and forward slash verify: https://8008.11-111-11-11-11.ngrok.io/verify.
And you will see this window.
Next we are going to add the TypingDNA Verify 2FA information to our code.
Run npm install typingdna-verify-client
.
const typingDnaVerifyClient = require("typingdna-verify-client");
const typingDnaClient = new typingDnaVerifyClient({
clientId: "1",
secret: "1",
applicationId: "1"
});
The clientID, secret and applicationID are available on the TypingDNA Dashboard.
To generate the ApplicationID, navigate to the Integration section and click on “Manage”.
Select “Add new integration”. Select a desired name under Integration name and under the domain please paste the ngrok domain (without https).
Then click on “Create integration” and a new integration will appear that will have an applicationID.
If you are running your website under a different domain please create a new integration.
Next we will generate the data attributes and we will update our router:
router.get("/verify", (req,res) => {
const typingDnaDataAttributes = typingDnaClient.getDataAttributes({
email: "demo@typingdna.com",
language: "EN",
mode:"standard"
});
res.render("verify", typingDnaDataAttributes);
});
Next we will pass the attributes to our page and we will modify the verify.pug file.
Add in the head section:
script(src="https://cdn.typingdna.com/verify/typingdna-verify.js")
Under H1 we will add our TypingDNA Verify button.
button(
class = "typingdna-verify",
data-typingdna-client-id= `${clientId}`,
data-typingdna-application-id= `${applicationId}`,
data-typingdna-payload= `${payload}`,
data-typingdna-callback-fn= "callbackFn"
) Verify 2FA with TypingDNA
After the user has typed the 4 words, an OTP code will be generated and the callbackFn will be called. In order to process this new OTP code we will add the following javascript code.
script.
function callbackFn(payload) {
window.location = window.origin + "/result" + "?otp=" + payload.otp
}
So our verify.pug file will look like this:
html
head
script(src="https://cdn.typingdna.com/verify/typingdna-verify.js")
script.
function callbackFn(payload) {
window.location = window.origin + "/result" + "?otp=" + payload.otp
}
body
h1 TypingDNA Verify 2FA
button(
class = "typingdna-verify",
data-typingdna-client-id= `${clientId}`,
data-typingdna-application-id= `${applicationId}`,
data-typingdna-payload= `${payload}`,
data-typingdna-callback-fn= "callbackFn"
) Verify 2FA with TypingDNA
Next we will implement our result page:
router.get("/result", (req,res) => {
const otp = req.query.otp;
typingDnaClient.validateOTP({
email:"demo@typingdna.com",
},otp)
.then((data) => {
res.render("result", {
success: `Authentication ${data.success === 1 ? "Successful" : "Failed"}`
});
});
});
And we will create a result.pug file.
html
body
h1 Results
h2=result
First we will set up Keycloak.
Create a new realm:
Add a new client.
Note: Under the root URL we will use the http link for now. Other configuration changes are required to be made in keycloak in order to handle https requests that are outside of the scope of this tutorial. TypingDNA Verify 2FA will only function if it’s running from HTTPS.
Navigate to the installation tab of the new client that you have created and copy the information from Keycloak OIDC_JSON.
Create a file called keycloak.json and copy the content:
Navigate to the users section.
Add a new user.
Select the password under credentials:
Navigate to the Roles page.
Create the role: “typingdna-keycloak”.
Then navigate to the role mapping tab of the user and assign the new created role to the user.
In order to integrate with keycloak we will add more dependencies in our package.json file:
Run npm install jwt-decode keycloak-connect express-session
At the beginning of the app.js file we will add:
const Keycloak = require("keycloak-connect");
const session = require("express-session");
const jwt_decode = require("jwt-decode");
const memoryStore = new session.MemoryStore();
const keycloak = new Keycloak({ store: memoryStore });
Add the following code.
app.use(
session({
secret: "secret1",
resave: false,
saveUninitialized: true,
store: memoryStore,
})
);
app.use(keycloak.middleware({ logout: "/logout" }));
Protect the verify page with keycloak and add the user from the keycloak token.
router.get("/verify", keycloak.protect("realm:realm:typingdna-keycloak"), (req,res) => {
const { access_token } = JSON.parse(req.session["keycloak-token"]);
const { email } = jwt_decode(access_token);
const typingDnaDataAttributes = typingDnaClient.getDataAttributes({
email: email,
language: "EN",
mode:"standard"
});
res.render("verify", typingDnaDataAttributes);
});
Add a new page to logout the user.
app.get("/logout", (req, res, next) => {
req.session.destroy();
res.clearCookie("connect.sid", { path: "/" });
return res.redirect("/");
});
Next we will update the result page to take the email into account and it will look like this:
router.get("/result", keycloak.protect("realm:typingdna-keycloak"), (req,res) => {
const otp = req.query.otp;
const { access_token } = JSON.parse(req.session["keycloak-token"]);
const { email } = jwt_decode(access_token);
console.log("keycloak email: ", email);
typingDnaClient.validateOTP({
email:email,
},otp)
.then((data) => {
if(data.success === 0) {
return res.redirect("/logout");
}
res.render("result", {result: "Authentication Successful"});
});
});
Start Keycloak and start the web application with the command node .\app.js
.
Access in a browser the ngrok link.
The user is redirected to the keycloak login page:
Enter the credentials and select the sign in button.
The user is redirected to the 2FA page.
Note: if the SSL/HTTPS redirect is not set up you will have to manually redirect the link. Adding SSL/HTTPS redirects is outside the scope of this tutorial.
Select the “Verify 2FA with TypingDNA” and type the 4 words presented on the screen.
Once the 4 words are typed the user is redirected to the result page where the message “Authentication Successful” is presented.
For more information please contact us at support@typingdna.com.