Skip to main content

· 5 min read
Mircea Nistor

We are excited to announce a new major release of Veramo!

This new release brings together a bunch of fixes and features that we've been working on recently, including some from the community (thank you for your contributions!).

You can get a detailed list of changes in the release description. Depending on how you're using Veramo you might be impacted by some breaking changes that had to be added in this release.

In Veramo 3.0 we've separated some responsibilities of different plugins that deal with key management. This enables people to create new kinds of key management systems for Veramo in a way that makes it clearer where private data is stored and reduces the risk of leaking.

As you may already be aware, Veramo has a 2 layer approach to plugins. On the first layer there are top-level agent plugins that can register for events and that export methods to be directly callable on the agent object. These plugin methods can also call each other in the same execution context.

In many cases these agent plugins provide some common API for interacting with different protocols or standards implementations. This is where the second level plugins come in. These provide specific implementations that plug-into the top-level ones. These implementations aren't expected to be aware of each-other, so they don't directly interact.

Examples of this pattern include DIDResolver with implementations for various DID methods, DIDManager with IDIDProvider implementations, and of course KeyManager with implementations of AbstractKeyManagementSystem ( We sometimes refer to these as KMS).

What's new about key management?

The @veramo/kms-local is an implementation of AbstractKeyManagementSystem. In the previous versions it was responsible for implementing some crypto algorithms, but it would rely on the top-level @veramo/key-manager to provide the actual private key material.

In Veramo 3.0 @veramo/key-manager no longer stores any private key material. Instead, @veramo/kms-local now uses a PrivateKeyStore for hosting the key data. The @veramo/data-store package provides an implementation that uses a database for storing these keys encrypted by a SecretBox.

This means there will be some changes for the initial setup of these plugins, and also some changes related to how the database connection is made.

This also means that keyManagerGet() no longer returns private keys**. If your use-case requires that you export keys from Veramo, please raise an issue, or contact us on the github discussions page.

Ok, so how does it affect me?

If you're just starting out, simply follow one of the getting started guides. Easy-peasy.

If you're already working with Veramo and wish to upgrade existing agents to 3.0, you'll have to make some changes to your configuration, depending on how you're using the framework.

It boils down to these 3 steps, but keep reading for more details:

  1. Update your database connection to use migrations
  2. Remove the SecretBox parameter from KeyManager
  3. Add a PrivateKeyStore parameter to KeyManagementSystem with a SecretBox that you were using before with KeyManager (and keep the same encryption key)

Typescript app config changes

If your agents are part of a typescript app, these changes will look like this:

import {
// ...
migrations, // 0. import default veramo migrations
PrivateKeyStore,
} from '@veramo/data-store'

// 1. update your connection config to use migrations
dbConnection = createConnection({
// ...
synchronize: false, // switch this to false
migrations, // add default veramo migrations
migrationsRun: true, // add this flag
})

const agent = createAgent<>({
// ...
plugins: [
// 2. key manager: remove SecretBox param
new KeyManager({
store: new KeyStore(dbConnection),
kms: {
// 3. kms-local: add PrivateKeyStore with SecretBox
local: new KeyManagementSystem(new PrivateKeyStore(dbConnection, new SecretBox(secretKey))),
},
}),
// ...
],
})

CLI config changes

# 0. update the version for your config file
version: 3.0
# ...

# 1. update your database connection to use migrations
dbConnection:
$require: typeorm?t=function#createConnection
$args:
- type: sqlite
database:
$ref: /constants/databaseFile
synchronize: false # switch off synchronize
migrationsRun: true # turn on migrations
migrations: # start with veramo default migrations
$require: '@veramo/data-store?t=object#migrations'
logging: false
entities:
$require: '@veramo/data-store?t=object#Entities'

# then update your keyManager config:
keyManager:
$require: '@veramo/key-manager#KeyManager'
$args:
- store:
$require: '@veramo/data-store#KeyStore'
$args:
- $ref: /dbConnection
# 2. remove the SecretBox argument from KeyManager
kms:
local:
$require: '@veramo/kms-local#KeyManagementSystem'
$args:
- $require: '@veramo/data-store#PrivateKeyStore'
$args:
- $ref: /dbConnection
# 3. add the SecretBox argument from KeyManager to your PrivateKeyStore
- $require: '@veramo/kms-local#SecretBox'
$args:
- $ref: /constants/secretKey

Easy, right?

The default migrations that we bundle with @veramo/data-store also take care of moving the encrypted keys to the new table. Make sure to use the same encryption key with SecretBox that you were using before to be able to decrypt the keys in their new location.

I was using my own AbstractKeyManagementSystem, what do I do now?

In that case, congrats! Let us know about it.

The most important thing to keep in mind is that KeyManager no longer holds any private key material. It only knows about which AbstractKeyManagementSystem holds the key.

This means that when a method like sign() is called on your KMS, you should only care about the kid property of the IKey param and nothing else.

Also, it is now the responsibility of the KMS implementation to compute publicKeyHex and to decorate a key with meta-data when it creates or imports it, before returning the descriptor to the calling KeyManager.


As always, if there are any issues, let us know abut them, and if there are questions, please use the discussions page to get them answered and stay tuned for more.

· 4 min read
Mircea Nistor

We are excited to announce a new major release of Veramo!

This new release brings together a bunch of fixes and features that we've been working on recently, including some from the community (thank you for your contributions!).

You can get a detailed list of changes in the release description. Depending on how you're using Veramo you might be impacted by some breaking changes that had to be added in this release.

Added support for DIDComm v2

Our @veramo/did-comm package got a boost of functionality with new support for DIDComm v2 over HTTP. This plugin now exports 3 new methods:

As you may have guessed, the existing sendMessageDIDCommAlpha1() method should no longer be used. We hope that the name of the method already suggested instability. This will be removed in Veramo 4.x.

To send a message you now pack it and then send the packed message:

const message = {
type: 'test',
to: receiver.did,
from: sender.did,
id: '123',
body: { hello: 'world' },
}
const packedMessage = await agent.packDIDCommMessage({
packing: 'authcrypt',
message,
})
const result = await agent.sendDIDCommMessage({
messageId: '123',
packedMessage,
recipientDidUrl: receiver.did,
})

According to DIDComm v2 spec, the recipient DID document must have a DIDCommMessaging service endpoint and a keyAgreementKey listed. The key agreement key is used to pack (encrypt) the message and the service endpoint is where the message is sent.

Added a basic plugin for DID discovery

We imagine that apps dealing with DIDs may need some look-up capabilities, so we created a DIDDiscovery plugin that can mediate this. Multiple DIDDiscovery providers will be asked to find matches based on a query string. We provide 2 basic providers for this, one covers DID aliases and another covers DIDs that are the subject of Credentials with a name claim.

const result = await agent.discoverDid({ query: 'alice' })

expect(result.results[0].matches[0]).toEqual({
did: 'did:example:some-did-with-alias-alice',
metaData: {
alias: 'alice',
},
})

These basic providers only look in the local database for these matches. Future providers could search other data stores, or find DIDs by keys or by .well-known/did-config matches... you name it. Imagination is the limit here.

Added generic signing and shared-secret capabilities

The @veramo/key-manager now exports 2 new methods:

  • keyManagerSign() - support all signing algorithms that lower level key management systems provide.
  • keyManagerSharedSecret() - compute shared secrets between a locally managed secret key and an external public key.

These are supposed to start phasing out the previous methods keyManagerSignJWT(), keyManagerSignEthTX() and keyManagerEncryptJWE()/keyManagerDecryptJWE().

The new signer can accommodate multiple algorithms implemented by your AbstractKeyManagementSystem implementations:

Example 1. signing JWT:

const jwsSignature = await agent.keyManagerSign({
algorithm: 'ES256K',
data: 'bla.bla',
encoding: 'utf-8',
keyRef: myKey.kid,
})

Example 2. signing an ethereum transaction:

const txData = serialize({
to: '0xce31a19193d4b23f4e9d6163d7247243bAF801c3',
value: 300000,
gasLimit: 43092000,
gasPrice: 20000000000,
nonce: 1,
})

const rawTx = await agent.keyManagerSign({
algorithm: 'eth_signTransaction',
data: txData,
encoding: 'hex',
keyRef: myKey.kid,
})

Get DIDComm v2 out of the box with @veramo/remote-server & did:web

If you are using @veramo/remote-server#WebDidDocRouter and @veramo/did-provider-web it is now easier than ever to receive DIDComm messages. The did-provider-web bootstraps your new did:web with Ed25519 and X25519 keys to be used for keyAgreement as well as listing an HTTP DIDCommMessaging endpoint by default.

Just as before, you still have to configure your express app with the proper hostname(s) to match your did:web identifiers.

Simpler setup for react-native

@veramo/kms-local-react-native is not needed any more. It is now replaced by @veramo/kms-local which can be used in all environments. Some extra ceremony is still needed on react-native but the overall experience should be simpler.

Take a look at the React-native tutorial to see how to set that up.


As always, if there are any issues, let us know abut them, and if there are questions, please use the discussions page to get them answered and stay tuned for more.

· 2 min read
Jason Healy

Throughout the development cycle of Veramo from its early alpha days as DAF, we have always had some form of user interface to help build and test features. The first UI was a React Native mobile application called daf-mobile which has since been deprecated.

Out of necessity for a fully working UI that makes working with agents easier and helps validate Veramo APIs among many other use-cases we created a simple dashboard called Agent Explorer.

As the Agent Explorer is a developer dashboard, the design was to be kept minimal and unobtrusive while surfacing the very pieces of technical information that would normally be hidden for non-developers. We also wanted this UI to be modular and flexible as Veramo is. We have not fully achieved this yet but we have implemented a widget based approach that allows developers to create their own dashboard widgets while developing features for Veramo perhaps in another codebase. And finally the explorer provides a quick and simple way to see what’s going on in your agents and can assist in interacting and quickly generating bulk data for research and experiments.

We have been using agent explorer internally for many months now and today we are open-sourcing the codebase.

There are a number of ways to use the explorer depending on your workflow. (1 + 2 are if you do not need to build any custom UI functionality in the explorer and just wish to interact with your agents)

  1. Run directly from npm: npx agent-explore serve. This will run on your localhost on port 5000.

  2. Visit https://explore.veramo.io and connect your running agent.

  3. Fork the agent-explorer repo and run locally. If you build a widget that you think is useful to have in the main repo and therefore available on https://explore.veramo.io then please open a PR/discussion and we will review!

Note that the explorer depends on another library that we have in the pipeline Veramo React. Veramo React makes it easy to use Veramo APIs in React/React Native. We plan to open source this library very shortly.

· 3 min read
Mircea Nistor

We are excited to announce a new feature release of Veramo!

This new release brings together a bunch of fixes and features that we've been working on recently, including many from the community (thank you for your contributions!).

You can get a detailed list of changes in the release description. Depending on how you're using Veramo you might be impacted by some breaking changes that had to be added in this release.

Veramo uses the latest DID spec

Since the DID spec is in a more stable state, we took the opportunity to upgrade the @veramo/did-resolver and other connected internals to match this new spec. This should not be affecting you unless you are directly using the agent.didResolve() method:

  • The return type is now DidResolutionResult instead of just DIDDocument
    • This result includes a didDocument and metadata about the document and resolution process.
    • Errors are no longer thrown by the resolution process, instead they are returned as properties of the didDocumentMetadata object.
  • Many DID resolvers (including the ones we maintain, (did:ethr and did:web) now use the verificationMethod property instead of publicKey, with the same contents.

If you are directly importing dependencies from the did-resolver / did-jwt stack, please make sure to use the latest versions of those for best compatibility.

Some changes to the CLI configuration

There are some slight changes to the @veramo/cli configuration, mostly around the veramo server. options. Check out the veramo docs to see how the CLI configuration file works.

Ngrok is no longer included

In previous version you could define ngrok configuration directly in agent.yml like so:

server:
ngrok:
connect: true
authtoken: XZY
subdomain: alice-did
region: eu

From now on, if you want to have the same functionality, you need to launch ngrok separately:

ngrok http -subdomain=alice-did -region=eu --authtoken=XZY 3000

and then update agent.yml file to use the correct baseUrl

server:
baseUrl: https://alice-did.eu.ngrok.io

Creating a default DID when initializing server

Previously this was controlled with this configuration:

server:
defaultDID:
create: true
messagingServiceEndpoint: /messaging

In the new version this was moved to a separate section:

server:
# Execute during server initialization
init:
- $require: '@veramo/remote-server?t=function#createDefaultDid'
$args:
- agent:
$ref: /agent
baseUrl:
$ref: /constants/baseUrl
messagingServiceEndpoint: /messaging

So if you don't need this functionality, instead of setting server.defaultDID.create to false, you can simply remove this section from your config file.

New plugin for did:key

This is an additional package that allows you to create, use and resolve did:key identifiers directly in Veramo.

To be able to create and manage did:key identifiers you'll have to add the provider to the DIDManager plugin:

import { KeyDIDProvider } from '@veramo/did-provider-key'

const agent = createAgent<>({
plugins: [
// ...
new DIDManager({
// ...
providers: {
// ...
'did:key': new KeyDIDProvider({
defaultKms: 'local',
}),
},
// ...

And then to create a did:key identifier:

const myKeyDid = await agent.didManagerCreate({ provider: 'did:key' })

As always, if there are any issues, let us know abut them, and if there are questions, please use the discussions page to get them answered and stay tuned for more.

· One min read
Jason Healy

We are excited to announce our first public beta of Veramo to the world!