Getting Started

Welcome to the uPort usage guide!

Here we will walk you through all the necessary steps to get up and running with your first dapp.

Web 3.0 and decentralized applications require a fundamental rethinking of the moving parts of the web so it is important to read everything or you may miss some important elements around the design decisions of what you are working with.

Also please note: these libraries are in progress and are subject to change. Gitter is a great place for the community to congregate and help each other. Lets get started.

Download the Mobile App

Firstly, we will download the uPort mobile app.

The mobile app is where your ECDSA private keys are held (inside the secure enclave that's unlocked with your fingerprint). These keys are what controls the administrative layer between your device and the blockchain.

You will also have locally stored data in the app that is relevant to you such as your contacts and verified credentials. Essentially, the phone is an extension of you, and uPort is your internet native passport to the secure, decentralized web.

You can download the mobile app with one of the links below.

uPort iOS | uPort Android

Once you have downloaded the app, go ahead and create an identity. This identity will be resident on the RINKEBY Ethereum test network. You can create more identities on the same netowrk or on other Ethereum networks (ROPSTEN and KOVAN) in the settings menu so you can test counterparty interactions on the same network.

Register your App

Next we shall regsiter an application on the blockchain.

When a users interacts with an app, they will desire to see relevant information, a picture, and any other helpful indicators on their transacation cards that this is the correct endpoint they wish to interact with. This registration process will create an identity for your app so that this becomes possible, and for your frontend to know where to listen to changes on the blockchain.

Let's go create an app over at the uPort App Manager.

Make sure to save the signing key somewhere secure! This will not be stored in browser for you for security reasons.

Install the Library/SDK

We now have the mobile uPort app and a registered application. Let's install the library in our project.

Please make sure you have Node.Js and NPM installed

uPort and its depending libraries are dependent on the Node.Js ecosystem.

Native (iOS & Android) Application libraries are in the works.

Go to your Terminal and cd to your project folder.

npm install --save uport-connect

Add your Keys

Now that we have the needed dependency, lets go grab our keys from the app manager.

You may copy the code with the injected keys in the accordion at the bottom of your created app's page to help you get started quickly or you can follow the directions below.

We need to instantiate the uPort object with an app's identity.

Lets create an object from the Connect function and feed in the App's name, id, and signing key.

const uport = new Connect('NAME_OF_DAPP', {
  clientId: 'CLIENT_ID',
  signer: SimpleSigner('SIGNING KEY')
})

The clientID is the public address of your app and the signer (wrapped with the SimpleSigner function) is the signing key of your app that you will help create JWT tokens. These bits of information are given to you after registering an application.

We should also export the web3 and MNID objects from the resulting uport object for signing transactions later.

const web3 = uport.getWeb3()
export { web3, uport, MNID }

Requesting Credentials

The first and most basic step you should take is to allow your user to connect their uPort to your app. The requestCredentials method is how you accomplish this, similar in concept to logging in , except there is no server session for you to manage. All you need to do to "connect" is to disclose the requested credentials you have in your uPort identity.

Calling the request method

By default the uport-connect library will fire a QR image inside of an injected global modal to help you get up and running quickly.

This can be disabled by intercepting the URI so you may use another library to customize the look and feel of the QR image. See Custom QR Styling

Once the user has scanned the displayed QR image, and has submitted their credentials, the promise should resolve with a Schema.org person JSON data payload. You can then handle this data however you desire in the then function.

// Basic usage with modal injection
uport.requestCredentials()
     .then((userProfile) => {
       // Do something after they have disclosed credentials
})

The expected payload should look like:

{
  "@context":"http://schema.org",
  "@type":"Person",
  "name":"Agent Smith",
  "address":"23fga3r2hh87ddhq98dhas8dz101j9f449w0",
  "avatar": {
    "uri": "https://ipfs.infura.io/ipfs/QmaqGAeHmwAi44T6ZrSuu3yxwiyHPxoE1rHGmKxeCuZbS7DBX"
  },
  "country": "US"
  "network":"rinkeby",
  "publicEncKey": "dgH1devHn5MhAcph+np8MI4ZLB2kJWqRc4NTwtAj6Fs="
  "publicKey":"0x04016751595cf2f1429367d6c83a826526g613b4f7574af55ded0364f0fb34600bceba9211e5864ae616d7e83b5e3c79f1c913b40c8d38c64952fef383fd3ad637",
}

Requesting specific credentials

You can request specific credentials by submitting an array of values in an array of the requested key of a passed object.

uport.requestCredentials({
  requested: ['name', 'avatar', 'phone', 'country'],
  }).then((userProfile) => {
    // Do something after they have disclosed credentials
})

Enabling Push Notifications

When a transaction is going to be signed, if the notifications flag is set to true it will allow any future transaction signing to fire a prompt in the uPort mobile app. For UX considerations, we encourage developers to use this, otherwise your users will have to scan a QR code per each interaction.

uport.requestCredentials({
  requested: ['name', 'avatar', 'phone', 'country'],
  notifcations: true
  }).then((userProfile) => {
    // Do something after they have disclosed credentials
})

Custom QR Styling (web)

We have had success with the KJUA QR Library. It's also recommended you wrap the QR or create a seperate button for mobile.

uport.requestCredentials({
  requested: ['name', 'avatar', 'phone', 'country'],
  notifcations: true },
  (uri) => {

    const qr = kjua({
      text: uri,
      fill: '#000000',
      size: 400,
      back: 'rgba(255,255,255,1)'
    })

    // Create wrapping link for mobile touch
    let aTag = document.createElement('a')
    aTag.href = uri

    // Nest QR in <a> and inject
    aTag.appendChild(qr)
    document.querySelector('#kqr').appendChild(aTag)
  }
  }).then((userProfile) => {
    // Do something after they have disclosed credentials
})

Logging in via Mobile (sdk)

Under construction

Attesting Credentials

One of the core needs of Web 3.0 is to build trust in a self-sovereign world. We establish facts which are not mathematically derived by social consensus. To create social consensus, actors must attest to things being true. We can do this with uPort using the uport.attestCredentials function.

NOTE: Currently only one credential can be pushed at a time. We are working to fix this soon.

Calling the attest method

uport.attestCredentials({
  sub: 'THE_RECEIVING_UPORT_ID',
  claim: { CUSTOM_PROPERTY: PROPERTY_VALUE },
})

Setting an expiration date

We can also optionally add an expiration date.

uport.attestCredentials({
  sub: 'THE_RECEIVING_UPORT_ID',
  claim: { CUSTOM_PROPERTY: PROPERTY_VALUE },
  exp: new Date().getTime() + 30 * 24 * 60 * 60 * 1000,  // Optional expiration
})

Attesting multiple credentials

Under construction

Signing Transactions

uPort comes pre-baked with a web3 instance that calls to Infura, our p2p swarm of nodes we have built so you don't need to stand up your own. All you need to do is grab our web3 object and instantiate a smart contract javascript object with a provided ABI.

Supply the contract ABI

An ABI (Application BINARY Interface) can be generated by compiling your smart contract with the Remix Web IDE. Its on the "Contracts" tab down where it says interface. You can deploy this contract to the chain with the Web3 deploy code just below that in your local Ethereum node console or with our build & deploy tool called Truffle.

Create the contract object

function MyContractSetup () {
  let MyContractABI = web3.eth.contract(PROVIDED_CONTRACT_ABI)
  let MyContractObj = MyContractABI.at(DEPLOYED_CONTRACT_ADDRESS_LOCATION)
  return MyContractObj
}
const MyContract = MyContractSetup()

Call a basic method on the contract

In a typical application, upon load, there is data usually being requested by a server to get the current state of the user's data. We must do the same here, but rather than reading a SQL database, we are instead reading the blockchain.

At ConsenSys we use our Web 3.0 infrastructure stack called Infura to make the amount of possible calls scalable. You could otherwise have an Ethereum node local on your machine with a downloaded copy of the blockchain you could query. Calls can be simulated without having a copy of the blockchain though using a local TestRPC node, but thats out of scope for this guide.

It is important to note that Ethereum has many networks, such as "intranet" style private networks, tests networks, and the main network everyone knows. In order to call a contract with our ID to look up some data, we must match the network that the identity is on and the the network the contract is on. To do this we will grab the uport address and break it out using the MNID or "Multi Netowork Identity" module supplied with uPort. Remember our requestCrednetials callback that gave us a Schema.org/Persona JSON payload? Lets go dig into that.

Lesson learned: uPort has 1 master address that is a hash of MANY addresses for all the different networks it exists on.

.then((userProfile) => {
  const decodedId = MNID.decode(userProfile.address)
  const specificNetworkAddress = decodedId.address
})

We could then supply specificNetworkAddress to where METHOD_INPUT_DATA is below.

// Basic call to get some return data, no transaction signing
MyContract.someMethod.call(METHOD_INPUT_DATA, (error, response) => {
  if (error) { throw error }
  console.log(response)
})

Call a tx signing method on the contract

Calling a method on a smart contract is essentially no different than that of a javascript function, except that solidity contracts cannot handle JSON objects, only strings and numbers.

// Transaction signing (that will fire a QR to scan or card in the mobile app)
MyContract.someMethod(METHOD_INPUT_DATA, (error, txHash) => {
  if (error) { throw error }
    waitForMined(txHash, { blockNumber: null }, // see next area
    function pendingCB () {
      // Signal to the user you're still waiting
      // for a block confirmation
    },
    function successCB (data) {
      // Great Success!
      // Likely you'll call some eventPublisherMethod(txHash, data)
    }
  )
})

Wait for mining to complete

When a transaction is signed and submitted to a smart contract, the Ethereum network takes time to mine (confirm) the transaction (typically 15 seconds). During this time we will need to poll the Web3 node (aka provider and in our case, its Infura), to see if its been mined. We will keep checking it with a function called waitForMined and have a pending callback and a success callback to manage state.

// Callback handler for whether it was mined or not
const waitForMined = (txHash, response, pendingCB, successCB) => {
  if (response.blockNumber) {
    successCB()
  } else {
    pendingCB()
      pollingLoop(txHash, response, pendingCB, successCB)
  }
}

// Recursive polling to do continuous checks for when the transaction was mined
const pollingLoop = (txHash, response, pendingCB, successCB) => {
  setTimeout(function () {
    web3.eth.getTransaction(txHash, (error, response) => {
      if (error) { throw error }
        if (response === null) {
          response = { blockNumber: null }
        } // Some ETH nodes do not return pending tx
        waitForMined(txHash, response, pendingCB, successCB)
    })
  }, 1000) // check again in one sec.
}

Server-side Credentials

Here we will demonstrate how to create and sign a custom credential on a server (called the Creator) and present this to a uport identity. The user of the uPort app will add this credential to her list of credentials. Then we'll show how another service (called the Requestor) can request this credential and validate the corresponding JSON Web Token.

Register The App

First we wish to create identities for our apps. You can skip this step if you're ok with using the default identities that are hardcoded in the tutorial files. To create identities, go to the uPort AppManager, connect with your uPort, and select "New App". This will create a uPort identity for your app, and will display a private key, which you will use on the server to sign credentials. It's important that you save this key!

Go ahead and create identities for the Creator and Requestor, or if you wish to skip this step we have created identities for these services already, with the private keys and addresses hard coded in the apps.

Creator service

In the file createcredential.js we have a simple node express server. In the setup phase we use the private key we got from the App Manager to create a SimpleSigner object. This object is what will be signing the credential.

var signer = uport.SimpleSigner(<your key here>)

We then create a Credentials object using the signer and the uPort identifier of our app that we got from the App Manager:

var credentials = new uport.Credentials({
  appName: 'Credential Tutorial',
  address: '2od4Re9CL92phRUoAhv1LFcFkx2B9UAin92',
  signer: signer
})

When we hit the default route using app.get('/') we will call credentials.attest() in order to sign the credential. For the fields of the credential, the sub field is the subject. Set this to the uPort Id of the user that is supposed to receive the credential. For testing purposes this would be the uPort identity shown on the mobile app of the reader. The exp field is the expiry of the token, in Unix time. As claim field, put your own custom object. We have here {'Custom Attestation' : 'Custom Value'} as an example.

credentials.attest({
  sub: '2oVV33jifY2nPBLowRS8H7Rkh7fCUDN7hNb',
  exp: 1552046024213,
  claim: {'Custom Attestation' : 'Custom Value'}
})

The attest() function returns a promise that resolves to a JSON Web Token. We're going to present this token to the user through a URL that looks like this:

me.uport:add?attestations=<JSON Web Token>

We present this to the user in the form of a QR code. When you scan this code with your mobile app you should see an alert that you are about to add a credential. It should reference the Creator app as the identity giving you this credential. This will add the credential locally to your phone.

When you're done editing the file you may run the Creator service like so:

> cd tutorial
> node createcredential.js

If you open your browser to http://localhost:8081/ you should see the QR code with the credential, which you may scan with the uPort app.

Requestor service

The file requestcredential.js contains a simple node express server which will request the same credential that the Creator service gave out. The Requestor server will then validate that the identity who is providing the credential is the same identity that received the credential from the Creator service.

As with the Creator service we start by setting up the Signer using the private key from the App Manager, and the Credentials object using the uPort identifier of our Requestor app. We also set up bodyParser so that we can parse the JWT that we will get back from the user.

When we load the app using app.get('/') we use createRequest() in order to request a specific credential from the user. Here we will request the Custom Attestation credential. We will use verified to denote which credentials we are requesting.

The callbackUrl field specifies where the mobile app user should send the credential, should she agree to share it. If you are running the app on a local network you should put your local IP address here, followed by the route /callback. Make sure your mobile device is connected to the same network. If you are running the app on a VPS service like Digital Ocean, make sure to put the correct IP address in and that the right ports are open.

We have an expiry field, denoted exp, which denotes how long the request will be valid. In our example we use 60 seconds (60000 milliseconds). This means that if the user waits longer than 60 seconds to provide the response their response will not be accepted as valid.

credentials.createRequest({
  verified: ['Custom Attestation'],
  callbackUrl: 'http://192.168.1.34:8081/callback',
  exp: new Date().getTime() + 60000
})

The createRequest() function creates a signed JWT containing the request. The mobile app can then validate that the correct app sent the request.

To interact with the server, run

node requestcredential.js

and go to http://localhost:8081 in your browser.

When the mobile app user approves the request to share her credential after scanning the code, the /callback route is called using app.post('/callback'). Here we fetch the response JWT using req.body.access_token.

Once we have the JWT we wish to validate it. We use the receive() function first. This validates the JWT by checking that the signature matches the public key of the issuer. This validation is done both for the overall JWT and also for the JWTs that are sent in the larger payload.

Next we check that the issuer of the response token (i.e. the user) matches the subject (sub field) of the returned credential, that the issuer of the returned credential is the Creator App, and that the credential is of the type Custom Attestation with value Custom Value.

If everything checks out, you should see the output

Credential verified.

in the console. Congratulations, you have verified the credential!

To test out everything, try checking for a different attestation and make sure it fails. Also try waiting longer than 60 seconds before sending the response to see if it fails - it should throw an error in this case.

Private Chain Deployment

The uPort platform supports deployment of our core infrastructure on private Ethereum blockchains. We're working on a self-serve deployment process, and in the meantime we're happy to help you get set up. Please email privatechain@uport.me to get started.