Offline Authentication in the Browser: Part 1 — WebCrypto API

Team Concords
3 min readDec 13, 2020

Authentication is something we generally associate with client-server communication, a way for a user to tell the server that they do in fact have access rights to its data.

A Concord app doesn’t communicate with a server or have a centralized database to access, but we still require a way to add identity into our applications.

To achieve a secure identity, we can use the Web Crypto API to generate a public/private key pair and add some sugar with the Vue 3 composition API to add a simple but effective authentication flow to our apps.

We’re going to be issuing a public/private key pair through the Web Crypto API, using the ECDSA (Elliptic Curve Digital Signature Algorithm). This will able to use sign and verify transactions, using a private key hash associated with a public identity.

const { publicKey, privateKey } = await crypto.subtle.generateKey({
name: "ECDSA",
namedCurve: "P-384",
}, true, ["sign", "verify"]);

Now we've created our key pair, we need to export the key for use within our application. We’re going to use the JWK type for our export keys so we’ll be able to implement a familiar authentication flow for our application.

const { exportKey } = crypto.subtle;const encodedPublicKey = exportKey('jwk', publicKey);
const encodedPrivateKey = exportKey('jwk', privateKey);

In the JWK key format, both keys share the public aspect of the key, what’s important to us here is the public key, and the encodedPrivateKey.d attribute of the private key. As long as we hold the public key and the unique JWK held in encodedPrivateKey.d, then we are able to create a unique signing key to identify is we are authenticated within the app.

To construct the signing key, we can merge the public key with our JWK and pass the "sign" key operation to the WebCrypto API importKey method.

const key = { ...encodedPublicKey, d: jwk };
crypto.subtle.importKey(
'jwk',
key,
{
name: 'ECDSA',
namedCurve: "P-384",
},
true,
["sign"],
);

Together, this module gives us the ability to create a new key-pair and simulate login through verifying the key signature. We can now put all of this into our authentication module ready to hook up to our UI.

// authentication.jsexport const create = async () => {
const { publicKey, privateKey } = await crypto.subtle.generateKey(
{ name: "ECDSA", namedCurve: "P-384" },
true,
["sign", "verify"]
);
const encodedPublicKey = await crypto.subtle.exportKey('jwk', publicKey); const encodedPrivateKey = await crypto.subtle.exportKey('jwk', privateKey); const jwk = encodedPrivateKey.d; return {
jwk,
key: encodedPublicKey,
};
};

export const login = (jwk, key) => {
if (!jwk) {
return;
}
delete key.key_ops; return crypto.subtle.importKey(
'jwk',
{ ...key, d: jwk },
{ name: 'ECDSA', namedCurve: "P-384" },
true,
["sign"],
);
};

In Part 2 we’ll cover how to hook up an offline authentication flow with the Vue 3 Composition API to build out a full offline authentication flow.

Part 2: https://concords.medium.com/offline-authentication-in-the-browser-part-2-hooking-up-ui-with-the-vue-3-composition-api-86ae0e7d31e5

Demo: https://offline-authentication.concords.app.

Source: https://github.com/teamconcords/offline-authentication

--

--