Skip to content

This project demonstrates how can a website implement logging in with web3 credentials using the KILT Protocol.

License

Notifications You must be signed in to change notification settings

KILTprotocol/web3-login-demo

Repository files navigation

web3-login-demo

Explanatory Tutorial for websites to implement logging in with web3 credentials using the KILT Protocol.

Intro

This project demonstrates how to enable login using KILT Protocol. It is an educational project, everything is broken down to little steps and has explanations to ease your understanding.

During the login procedure, the user is required to present a credential. You can decide which credentials to accept. They could be issued by yourself or by other attesters.

If you require the credentials to be attested by yourself, the credentials become similar to membership cards. If you also accept credentials from other attesters, you open your system up to also accept other membership cards.

This means that users don't not need to setup an account and password just for your website. Additionally, this avoids third parties (usually powerful data-collecting companies) from tracking your interactions with your clients. There is no trace on the KILT blockchain about the interaction between you and your client.

In order for a dApp to support logging in with KILT Credentials, it needs:

  1. It's on-chain DID
  • This DID is used so that the user knows the parties to whom they talk.
  1. It's Domain Linkage Credential
  • Bind your DID to a specific domain.
  • This prevents Man-in-the-Middle attacks.
  • Also known as the well-known-did-configuration.
  1. A CType to request from the user
  • The type of credentials the dApp considers valid.
  • The CType defines the structure and semantics of the credential you accept.
  • The issuer of this credentials is important. Anyone can issue a credential of a CType, but not everybody can be trusted as a source of truth.
  • To be secure, your dApp should accept credentials coming from it's trusted attesters.

If you don't have some of the above, don't worry, we help you get them on the sections below.

After setting up and running this project locally on your computer, you will have representation of how the login process works. You are free to copy code from here, but we do encourage you to customize the code for your specific use case. Just keep in mind to follow the specifications to retain compatibility with the wallets/extensions.

If you are rather looking for a Plug-and-Play solution, we provide the openDID project which implements the OpenID-Connect implicit flow to authenticate your users. OpenDID substantially reduces the complexity of integration.

Users requirements

It is important, that the dApp and the user interact with information from the same chain. There is the KILT Test Chain aliased Peregrine. And there is the production KILT Chain aliased Spiritnet.

For a user to log in with KILT, it requires:

  1. A compatible wallet or extension.
  1. An on-chain DID
  1. A Credential that the dApp considers valid.
  • This means the credential has to (simultaneously) be:

    • one of the cTypes accepted by the dApp.
    • issued by one of the dApps trusted attesters.

Steps to launch the dApp locally

  1. Clone repository and install all necessary modules.
  2. Define your environment variables
  3. Build a Domain Linkage Credential
  4. Start your dApp

Prerequisite

This code makes use of a mix of different technologies. If you are not familiar with some of these, we recommend to first get an overview about them.

Installation

After cloning the repository, to install all required modules

  • run: yarn install.

Environment Variables

Before you can run this project, you need to setup your environment variables. This variables specify which blockchain we use and they hold the secrets for your DID and to sign JWTs. Defining them is part of the set up of your project.

The .env-file should be on the root directory of this repository. This file maybe hidden. It is included on the .gitignore list so that the secrets that are contained in the file never get pushed to GitHub. There is a .env.example-file that also list how your variables should be named. The .env-file should be added to the same level (directory) where .env.example-file is found.

The following variables are required:

  • WSS_ADDRESS = This is the websocket address of the RPC node
  • FRONTEND_PORT = This is the local Port on which your website (client-side) would be reachable
  • BACKEND_PORT = This is the local Port on which your server would be reachable
  • DAPP_ACCOUNT_MNEMONIC = This is the mnemonic of the Kilt account paying for all transactions
  • DAPP_DID_MNEMONIC = This is the mnemonic of the Kilt DID that identifies your dApp
  • DAPP_DID_URI = This is the URI of the Kilt DID that identifies your dApp
  • DAPP_NAME = This should be a custom name for your dApp
  • JWT_SIGNER_SECRET = This is secret key (string) that signs the Json-Web-Tokens before saving them in the Cookies
  • CTYPE_HASH = This is the type of credential (CType) your dApp will request from users for login. If you want to specify more than one CType, you can do so by adding a '/' sign between them
  • TRUSTED_ATTESTERS = This is a list of attester DIDs (CSV, separated by ','). Only credentials issued by these attesters will be considered valid. If you are using more than one CType, indicate the groups of trusted attesters by respectively separating them with a '/' sign.
  • REQUIRED_PROPERTIES = This is a subset of CType properties (CSV, separated by ',') required to be exposed on credential presentation. If you are using more than one CType, indicate the groups of required properties by respectively separating them with a '/' sign.

Info about Example/Recommended cTypes

This table provides information on recommended cTypes for SocialKYC credential issuance. SocialKYC is a platform that issues credentials based on user social media presence. The cType-hash is consistent across both Spiritnet and Peregrine to ensure interoperability and consistent verification across the KILT network by using universal identifiers stored on archive nodes.

SocialKYC on Spiritnet:

did:kilt:4pnfkRn5UurBJTW92d9TaVLR2CqJdY4z5HPjrEbpGyBykare

SocialKYC on Peregrine:

did:kilt:4pehddkhEanexVTTzWAtrrfo2R7xPnePpuiJLC7shQU894aY

Here are the cTypes recommended for SocialKYC:

Title CTYPE_HASH SocialKYC on Spiritnet SocialKYC on Peregrine Properties
Email 0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac prod. Spiritnet prod. Peregrine Email
Twitter 0x47d04c42bdf7fdd3fc5a194bcaa367b2f4766a6b16ae3df628927656d818f420 prod. Spiritnet prod. Peregrine Twitter
Discord 0xd8c61a235204cb9e3c6acb1898d78880488846a7247d325b833243b46d923abe prod. Spiritnet prod. Peregrine Discriminator, User ID, Username
GitHub 0xad52bd7a8bd8a52e03181a99d2743e00d0a5e96fdc0182626655fcf0c0a776d0 prod. Spiritnet prod. Peregrine GitHubUsername, Username
Twitch 0x568ec5ffd7771c4677a5470771adcdea1ea4d6b566f060dc419ff133a0089d80 prod. Spiritnet prod. Peregrine User ID, Username
Telegram 0xcef8f3fe5aa7379faea95327942fd77287e1c144e3f53243e55705f11e890a4c prod. Spiritnet prod. Peregrine First name, Last name, User ID, Username
YoutubeChannel 0x329a2a5861ea63c250763e5e4c4d4a18fe4470a31e541365c7fb831e5432b940 prod. Spiritnet prod. Peregrine Channel ID, Channel Name

Note: We only recommend these cTypes and properties for SocialKYC verification. Users are advised to select the appropriate properties based on their verification needs.

Additionally, for access to a broader range of CType Hashes, consider visiting the CType Hub.

Setup your environment

You have three different options:

  1. Using yarn environment:

    There is a script to facilitate the generation of the environment variables inside of this repository. This script is called ./launchScripts/genesisEnvironmentVariables.ts.

    • You can execute it by running yarn environment.

    Setting up your environment with this script is a step by step process. You will need to run the script repeatedly and follow the instructions that it provides, depending on your project's state. After running this script each time, you need to manually copy the output and save it on the .env-file .

  2. Using the kilt-distillery-cli

    This is a Command Line Interface tool that can help you obtaining this variables and also does other common tasks (unrelated to this project). The distillery uses the same key derivation as this repository, which means that it is highly compatible.

  3. Without help:

    If you are a pro, you could defined and generate them externally and add them to the .env-file. You would probably have to modify the generateKeyPairs.ts files (on the backend) to match your key derivation though.

Well-Known DID Configuration

After having all your environment variables, execute the following to build a Domain Linkage Credential:

  • yarn run did-configuration.

If you want know more about this, check out the Identity Foundation Documentation on Well-Known DID Configuration. Our dApp documentation also have a section about this.

Starting the dApp locally

After having all your environment variables and your well-known DID configuration run:

  • yarn start.

Login Process

After having set up the whole project, when the website is up and running, the login process can take place. Each user that wants to login would trigger the process that is displayed below. The process consist of multiple HTTP(S) queries, including extension-api's messages. Interactions are between the client (browser), the extension/wallet and the server (backend).

A user could trigger the whole process with just one click on the website, for example "Login with extension X" or "Login with extension Y".

On this example project, several (2-3) interactions are need because it is broken down into little steps. We encourage you to open and read the browser's and backend's consoles. This should help you understand what is happening on each step, which function is responsible for what, how did the cookies changed.

+-----------+                                                   +---------+                                                                 +---------+
| Extension |                                                   | Browser |                                                                 | Server  |
+-----------+                                                   +---------+                                                                 +---------+
      |                                                              | ------------------------\                                                 |
      |                                                              |-| User visits web3login |                                                 |
      |                                                              | |-----------------------|                                                 |
      |                                                              | --------------------------------------\                                   |
      |                                                              |-| User chooses an Extension X         |                                   |
      |                                                              | | and clicks on the "Connect" button. |                                   |
      |                                                              | |-------------------------------------|                                   |
      |                                                              |                                                                           |
      |                                please allow use on this page |                                                                           |
      |<-------------------------------------------------------------|                                                                           |
      | -------------------------------------------------------\     |                                                                           |
      |-| Only the "Extension X" pops up, only the first time. |     |                                                                           |
      | |------------------------------------------------------|     |                                                                           |
      | ---------------------------------------\                     |                                                                           |
      |-| The Domain Linkage Credentials under |                     |                                                                           |
      | | .well-known/did-configuration.json   |                     |                                                                           |
      | | is verified.                         |                     |                                                                           |
      | |--------------------------------------|                     |                                                                           |
      |                                                              |                                                                           |
      | User granted access                                          |                                                                           |
      |------------------------------------------------------------->|                                                                           |
      |                                                              |                                                                           |
      |                                                              | GET /api/session/start                                                    |
      |                                                              |-------------------------------------------------------------------------->|
      |                                                              |                                                                           |
      |                                                              |                                                                    200 OK |
      |                                                              |        set-cookie: sessionJWT={dAppName, dAppEncryptionKeyUri, challenge} |
      |                                                              |                               {dAppName, dAppEncryptionKeyUri, challenge} |
      |                                                              |<--------------------------------------------------------------------------|
      |                                                              |                                                                           |
      |      startSession(dAppName, dAppEncryptionKeyUri, challenge) |                                                                           |
      |<-------------------------------------------------------------|                                                                           |
      |                                                              |                                                                           |
      | {encryptionKeyId, encryptedChallenge, nonce}                 |                                                                           |
      |------------------------------------------------------------->|                                                                           |
      |                                                              |                                                                           |
      |                                                              | POST /api/session/verify                                                  |
      |                                                              | Cookie: sessionJWT={dAppName, dAppEncryptionKeyUri, challenge}            |
      |                                                              | {encryptionKeyId, encryptedChallenge, nonce}                              |
      |                                                              |-------------------------------------------------------------------------->|
      |                                                              |                     ----------------------------------------------------\ |
      |                                                              |                     | Verify sessionJWT.                                |-|
      |                                                              |                     | Decrypt challenge using nonce and encryptionKeyId | |
      |                                                              |                     | Verify Extension Session:                         | |
      |                                                              |                     | Assert that jwt-challenge (our)                   | |
      |                                                              |                     | and decrypted-challenge (theirs) match.           | |
      |                                                              |                     |---------------------------------------------------| |
      |                                                              |                                                                           |
      |                                                              |                                                                    200 OK |
      |                                                              |      set-cookie: sessionJWT={{dAppName, dAppEncryptionKeyUri, challenge}, |
      |                                                              |                             {encryptionKeyId, encryptedChallenge, nonce}} |
      |                                                              |<--------------------------------------------------------------------------|
      |               ---------------------------------------------\ |                                                                           |
      |               | Server-Extension-Session established ✉️ ⛓️ |-|                                                                            |
      |               |--------------------------------------------| |                                                                           |
      |                                                              | -----------------------\                                                  |
      |                                                              |-| User clicks on Login |                                                  |
      |                                                              | |----------------------|                                                  |
      |                                                              |                                                                           |
      |                                                              | GET /api/credential/login/request                                         |
      |                                                              | Cookie: sessionJWT                                                        |
      |                                                              |-------------------------------------------------------------------------->|
      |                                                              |       ------------------------------------------------------------------\ |
      |                                                              |       | The Server is asking for a Credential of a cType from the User. |-|
      |                                                              |       |-----------------------------------------------------------------| |
      |                                                              |                                                                           |
      |                                                              |                                                                    200 OK |
      |                                                              |                            set-cookie: credentialJWT={challengeOnRequest} |
      |                                                              |                                               KiltMsg{request-credential} |
      |                                                              |<--------------------------------------------------------------------------|
      |                                                              |                                                                           |
      |                            send(KiltMsg{request-credential}) |                                                                           |
      |<-------------------------------------------------------------|                                                                           |
      | -----------------------------------\                         |                                                                           |
      |-| User approves the request        |                         |                                                                           |
      | | and selects credential to share. |                         |                                                                           |
      | |----------------------------------|                         |                                                                           |
      |                                                              |                                                                           |
      | KiltMsg{submit-credential}                                   |                                                                           |
      |------------------------------------------------------------->|                                                                           |
      |                                                              |                                                                           |
      |                                                              | Post /api/credential/login/submit                                         |
      |                                                              | Cookie: credentialJWT                                                     |
      |                                                              | KiltMsg{submit-credential}                                                |
      |                                                              |-------------------------------------------------------------------------->|
      |                                                              |                      ---------------------------------------------------\ |
      |                                                              |                      | Verify the credential.                           |-|
      |                                                              |                      | Note the DID inside the credential.              | |
      |                                                              |                      | If verification was successful,                  | |
      |                                                              |                      | DID was authenticated with provided credentials. | |
      |                                                              |                      |--------------------------------------------------| |
      |                                                              |                      ---------------------------------------------------\ |
      |                                                              |                      | The login with credential process was completed. |-|
      |                                                              |                      | An authentication token is given to the user.    | |
      |                                                              |                      | It's all like web2 from here on.                 | |
      |                                                              |                      |--------------------------------------------------| |
      |                                                              |                                                                           |
      |                                                              |                                                                    200 OK |
      |                                                              |                                set-cookie: accessJWT{authenticationToken} |
      |                                                              |<--------------------------------------------------------------------------|
      |                                                              |                                                                           |

Deployed Version

We have deployed this demo dApp as well, making it accessible online. This allows the developers to compare their results. It also makes it possible for non-coders to it check out.

Reach the version connected to the KILT Production Chain aliased Spiritnet:

Reach the version connected to the KILT Development Chain aliased Peregrine:

Build

Running the app locally on your computer doesn't require this step. It's only necessary when you plan to deploy the app, not for the tutorial.

To obtain a production-ready version of the app, you can compile both the frontend and backend code into Docker images. For this, after having all your environment variables and your well-known DID configuration:

  • run yarn build.

About

This project demonstrates how can a website implement logging in with web3 credentials using the KILT Protocol.

Resources

License

Stars

Watchers

Forks

Packages

No packages published