node.jsauthenticationnext.jswebauthnfido-u2f

How to use U2F with NextJS


I am trying to implement U2F in my NextJS project. Currently I am using NextJS 13 (beta). I already have the server side code working with the u2f library but how do I implement it on the client side?

const U2F = require("u2f");
const Express = require("express");
const BodyParser = require("body-parser");
const Cors = require("cors");
const HTTPS = require("https");
const FS = require("fs");
const session = require("express-session");

const APP_ID = "https://localhost:2015";

const server = Express();

server.use(session({ secret: "123456", cookie: { secure: true, maxAge: 60000 }, saveUninitialized: true, resave: true }));
server.use(BodyParser.json());
server.use(BodyParser.urlencoded({ extended: true }));
server.use(Cors({ origin: [APP_ID], credentials: true }));

let user;

server.get("/register", (request, response, next) => {
    request.session.u2f = U2F.request(APP_ID);
    response.send(request.session.u2f);
});

server.post("/register", (request, response, next) => {
    const registration = U2F.checkRegistration(request.session.u2f, request.body.registerResponse);
    if(!registration.successful) {
        return response.status(500).send({ message: "error" });
    }
    user = registration;
    response.send({ message: "The hardware key has been registered" });
});

server.get("/login", (request, response, next) => {
    request.session.u2f = U2F.request(APP_ID, user.keyHandle);
    response.send(request.session.u2f);
});

server.post("/login", (request, response, next) => {
    const success = U2F.checkSignature(request.session.u2f, request.body.loginResponse, user.publicKey);
    response.send(success);
});

HTTPS.createServer({
    key: FS.readFileSync("server.key"),
    cert: FS.readFileSync("server.cert")
}, server).listen(443, () => {
    console.log("Listening at :443...");
});

Edit: What I found out is that you should use WebAuthn these days. Do any of you have a good tutorial that explains how to use it with nextjs?


Solution

  • EDIT: maybe this will suit you better as it is already implemented in react: https://github.com/csalas-yubico/webauthn-client

    Well, i couldn't do a better demo than already exists and is open source at https://webauthn.org, you can check the source code here https://github.com/webauthn-open-source/webauthn-yubiclone and find more info about the WebAuthn reference implementation here https://github.com/webauthn-open-source/webauthn-simple-app/ I think that will provide you with a good start to implement the client side of it. It has nothing to do with the framework you are using, e.g. Next.js or whatever, there is an ES6 branch for that reference implementation here https://github.com/webauthn-open-source/webauthn-simple-app/tree/es6-module so you could go from there when using a modern web framework.

    But in short, you basically initialize the library and do either register your U2F key or login with an already registered key, very simplified you have to implement these two scenarios into your client-side component/frontend:

    // register a new device / account
    var waApp = new WebAuthnApp()
    waApp.username = "me";
    waApp.register()
        .then(() => {
            alert("You are now registered!");
        })
        .catch((err) => {
            alert("Registration error: " + err.message);
        });
    
    // log in to a previously registered account
    var waApp = new WebAuthnApp()
    waApp.username = "me";
    waApp.login()
        .then(() => {
            alert("You are now logged in!");
        })
        .catch((err) => {
            alert("Log in error: " + err.message);
        });