Build web apps with Ceramic and 3ID Connect

Being able to use Ceramic directly from the convenience of your web browser is one of the core functionalities required to fulfill the vision of a permissionless dataweb. 3ID Connect enables this by providing a sandboxed IdentityWallet instance which users can authenticate to using any of their existing Ethereum wallets, and soon other Blockchain wallets as well. This tutorial will show you how to combine 3ID Connect with Ceramic in order to start building your app using dynamic, tamper resistant documents!

Using Ceramic on the web

The Typescript Ceramic implementation provides two main ways to interact with the ceramic network, Ceramic Core and Ceramic http-client. The former implements the entire protocol and relies on a js-ipfs instance to be available, the latter relies on a Ceramic Daemon which you can run from your terminal. Both of these implementations consume a DID Provider which is used to communicate with a wallet with DID support (see EIP2844). In the Building on Clay tutorial we described how to use the http client together with an instance of IdentityWallet. This is good if you want to dive into fundamentals, but 3ID Connect enables us to connect to a DID directly from the comfort of your browser-based Ethereum wallet. This DID will also be linked together with the ethereum address using IDX.

In this tutorial we will be using Ceramic Core, which means that we’re running the entire Ceramic protocol inside of the browser!

Setup 3ID Connect with Ceramic

First let’s install the needed packages. Currently the 3ID Connect version with Ceramic support is available using the next flag. In the example we will be using ceramic-core, but you can use ceramic-http-client as well.

$ npm install --save @3id/connect @ceramicnetwork/ceramic-core

Using 3ID Connect to authenticate to Ceramic is fairly straight forward once the basic flow is setup. In the example below we use an “injected ethereum provider” that’s available on window.ethereum. You can of course use any ethereum provider that you like.

import { ThreeIdConnect, EthereumAuthProvider } from '@3id/connect'
const threeIdConnect = new ThreeIdConnect()
// Usually the following three steps are taken when
// a user choose to connect their wallet
const addresses = await window.ethereum.enable()
// Create 3id connect instance
const authProvider = new EthereumAuthProvider(window.ethereum, addresses[0])
await threeIdConnect.connect(authProvider)
// create a Ceramic instance
import Ceramic from '@ceramicnetwork/ceramic-core'
import IPFS from 'ipfs'
const ipfs = await IPFS.create()
const ceramic = await Ceramic.create(ipfs)

// Give Ceramic a DID resolver and provider
import ThreeIdResolver from '@ceramicnetwork/3id-did-resolver';
import KeyDidResolver from 'key-did-resolver';
import { Resolver } from 'did-resolver';
import { DID } from 'dids';

const resolver = new Resolver({
    ......ThreeIdResolver.getResolver(ceramic),
    ......KeyDidResolver.getResolver(),
  });
const provider = await threeIdConnect.getDidProvider()
const did = new DID({ resolver, provider })
await ceramic.setDID(did)
await ceramic.did.authenticate()

Create documents in the browser

We can now start using Ceramic directly in the browser! Below are just some examples that you can also try out on the Web Playground which comes with 3ID Connect and Ceramic already set up. First, open the developer console and then click connect. The 3ID Connect modal will appear, and once approved, you will see “Connected with DID: did:3:<yourDID>” in the console. Once this appears, then you can run the below commands directly in the console. Note, if you’d like to reset the 3ID Connect iFrame state, clear application data for 3idconnect.org from localStorage.

const jsonSchema = {
  "type": "object",
  "$schema": "<http://json-schema.org/draft-07/schema#>",
  "required": [
    "title",
    "description"
  ],
  "properties": {
    "title": {
      "type": "string"
    },
    "description": {
      "type": "string"
    }
  },
  "additionalProperties": false
}
const doc1 = await TileDocument.create(ceramic, jsonSchema )
// This will throw an error because it's missing the "description":
const doc2 = await TileDocument.create(
  ceramic,
  { "title": "Client Document" },
  { schema: doc1.id },
)
// Uncaught Error: Validation Error: data should have 
// required property 'description'
// We can create the document if we provide all required fields:
const doc3 = await TileDocument.create(
  ceramic,
  {
    title: "Client Document",
    description: "A Ceramic Document created from the browser."
  },
  { schema: doc1.id },
)
// Now we can of course also update the document:
await doc3.update({
  title: 'Client Document',
  description: 'This document has now been updated from the browser'
})

That’s it for this tutorial! Hope you found it useful and thanks for reading. If you want to dive deeper have a look at the js-ceramic Github repo, and jump into our Discord.