Install | Usage | Example | Data Standards | API Docs
This is a library which allows you to set, get, and remove private and public data associated with an ethereum account. It can be used to store identity data, user settings, etc. by dapps that use a web3 enabled browser. The data will be retrievable as long as the user has access to the private key for the used ethereum account. The data is encrypted and can not be read by any third party that the user hasn't authorized. There is one shared space for data which all authorized dapps access by default, then there are spaces which dapps have to request explicit consent to access.
Install 3box in your npm project:
$ npm install 3box
Import the 3box module
const Box = require('3box')
Import using the dist build in your html code
<script type="text/javascript" src="../dist/3box.js"></script>
Or optionally by loading remote copy from unpkg CDN.
<!-- The most recent version -->
<script src="https://unpkg.com/3box/dist/3box.js"></script>
<!-- The most recent minified version -->
<script src="https://unpkg.com/3box/dist/3box.min.js"></script>
<!-- Load specific versions by specifying the version as follows -->
<script src="https://unpkg.com/3box@<version>/dist/3box.js"></script>
3Box allows users to create a public profile for their Ethereum address. In your dapp you might have multiple ethereum addresses that you would like to display a name, image, and other basic social metadata for. The getProfile
method allows you to fetch the public profile of any ethereum address (if it has one). This is a static method so you can call it directly from the Box object.
const profile = await Box.getProfile('0x12345abcde')
console.log(profile)
3Box allows applications to create, read, update, and delete public and private data stored in a user's 3Box. To enable this functionality, applications must first open the user's 3Box by calling the openBox method. This method prompts the user to authenticate (sign-in) to your dapp and returns a promise with a threeBox instance. You can only update (set, get, remove) data for users that have authenticated to and are currently interacting with your dapp. Below ethereumProvider
refers to the object that you would get from web3.currentProvider
, or window.ethereum
.
Calling the openBox method will open a new 3Box session. If the user's ethereum address already has a 3Box account, your application will gain access to it. If the user does not have an existing 3Box account, this method will automatically create one for them in the background.
const box = await Box.openBox('0x12345abcde', ethereumProvider)
When you first open the box in your dapp all data might not be synced from the network yet. You should therefore add a listener using the onSyncDone
method. This will allow you to know when all the user's data is available to you. We advise against setting any data before this sync has happened. However, reading data before the sync is complete is fine and encouraged - just remember to check for updates once this callback is fired!
box.onSyncDone(yourCallbackFunction)
You can now use the box
instance object to interact with public and private data stored in the user's profile. In both the public and the private data store you use a key
to set a value
.
// use the public profile
// get
const nickname = await box.public.get('name')
console.log(nickname)
// set
await box.public.set('name', 'oed')
// remove
await box.public.remove('name')
// use the private store
// get
const email = await box.private.get('email')
console.log(email)
// set
await box.private.set('email', '[email protected]')
// remove
await box.private.remove('email')
const fields = ['name', 'website', 'employer']
const values = ['Jon Schwartz', 'openworklabs.com', 'Open Work Labs']
await box.public.setMultiple(fields, values)
const privateFields = ['age', 'coinBalance']
const privateValues = ['xxx', 'yyy']
await box.private.setMultiple(privateFields, privateValues)
A space is a named section of a users 3Box. Each space has both a public and a private store, and for every space you open the user has to grant explicit consent to view that space. This means that if your dapp uses a space that no other dapp uses, only your dapp is allowed to update the data and read the private store of that particular space. To open a space called narwhal
you simply call:
const space = await box.openSpace('narwhal')
Interacting with data in a space is done in the same way as interacting with box.public
and box.private
(see here). For example:
const config = await space.private.get('dapp-config')
Threads are a shared datastore that enable decentralized communication between users, by allowing one or more users to post messages in a sequence. This functionality is great for adding commenting, chat, messaging, feed, and stream features to your application. Threads are saved within a space and users that join a thread (with the same name, in the same space) will be able to communicate in that thread.
For the fully detailed spec, view the documentation.
WARNING: this is an experimental feature, the API will likely change in the future!
You can get all posts made in a thread without opening a space. This is great for allowing visitors of your site view comments made by other users. This is achieved by calling the getThread
method on the Box object.
const posts = await Box.getThread(spaceName, threadName)
console.log(posts)
However if applications want to add interactivity to the thread, such as allowing the user to post in a thread or follow updates in a thread, you will need to open their space to enable additional functionality.
To post in a thread, a user must first join the thread.
const thread = await space.joinThread('myThread')
This allows the user to add a message to the thread. The author of the message will be the user's 3Box DID. When a user posts in a thread, they are automatically subscribed to the thread and it is saved in the space used by the application under the key thread-threadName
.
await thread.post('hello world')
This allows applications to get the posts in a thread.
const posts = await thread.getPosts()
console.log(posts)
This allows applications to listen for new posts in the thread, and perform an action when this occurs, such as adding the new message to the application's UI.
thread.onNewPost(myCallbackFunction)
You can quickly run and interact with some code by looking at the files in the /example
folder. You run the example with the following command:
$ npm run example:start
This runs a simple server at http://localhost:3000/
that serves the static example/index.html
file. This allows it easily interact with metamask. You can edit the example/index.html
file to try differnt code.
If you only want to fetch profile data from 3Box's profile APIs you can optimize by importing only those functions or the API specific dist file. Since this includes minimal dependencies, file size is ~ 80kb vs 4+mb for the full build.
const { profileGraphQL, getProfile, getProfiles, getVerifiedAccounts } = require('3box/lib/api')
<script src="https://unpkg.com/3box/dist/3box.api.min.js"></script>
Dapps can store data about users that relate to only their dapp. However we encurage dapps to share data between them for a richer web3 experience. Therefore we have created Key Conventions in order to facilitate this. Feel free to make a PR to this file to explain to the community how you use 3Box!
Use the idUtils
module to validate claims. See
the did-jwt library for more details.
const { idUtils } = require('3box')
const claim = 'eyJ0eX...'
idUtils.verifyClaim(claim)
.then(valid => console.info('details:', valid)
.catch(err => console.error('claim verification failed:', err)