Storage Connector

This section aims to describe how you can build a storage provider connector for the Axone protocol. We will implement here a simple storage proxy using the Axone SDK and expose it over HTTP.

Functional Specification

The storage proxy will allow the following features:

  • Authentication: Given an authentication verifiable credential, the proxy will authenticate the identity;

  • Read: Allow or not read access to a stored resource based on the governance rules of both the storage service & the requested resource;

  • Store: Allow or not to store a resource based on the governance rules of the storage service, issuing a verifiable credential expressing the publication of the stored resource;

Proxy implementation

To instantiate the proxy we'll need first some element to provide.

In order to issue credentials verifiable on-chain, the storage service must have a set of keys to provide cryptographic proofs, let's create them:

key, err := keys.NewKeyFromMnemonic(mnemonic)

It'll need also to establish a connection with the Axone blockchain to be able to interact with it, let's create a client for that purpose:

dataverseClient, err := dataverse.NewQueryClient(
    context.Background(),
    nodeGrpcAddr, // The gRPC address of an Axone node
    dataverseAddr, // The address of the dataverse smart contract
    grpc.WithTransportCredentials(insecure.NewCredentials()), // Use insecure credentials for demo purposes
)

For the management of verifiable credentials the proxy will need to resolve JSON-LD contexts, let's create a resolver for that purpose:

We now have all the elements to instantiate the proxy:

Expose over HTTP

At this point we have a fully functional storage proxy, but it is not available through any communication protocol, let's expose it over HTTP.

We'll expose an API with three endpoints:

  • POST /authenticate: Authenticate an identity given a verifiable credential and return a JWT token that must be used to access other endpoints;

  • GET /{resourceID}: Read a resource given its DID, the JWT token must be provided in the Authorization header as a bearer token;

  • POST /{resourceID}: Store a resource given its DID, the JWT token must be provided in the Authorization header as a bearer token;

Full source

Until now we saw only separate snippets for pedagogic purpose, let's see what it looks like when we put everything together in a single main.go:

Don't take this implementation as production-grade, it suffers from many issues. It is only a starting point to build your own storage connector.

Last updated