uPort

Workshop

andres.junge@consensys.net

@ajunge_m

Ethereum Madrid Hackathon 2019

node.js

npm

create-react-app

uPort Mobile App

http://bit.ly/uport-madrid

https://slides.com/ajunge/uport-workshop-ethmadrid

1 b. the characteristics determining who or what a person or thing is.

I'm Andrés

so...who/what are you?

I'm a father

I'm a contractor

I'm aquarius

I'm Chilean

I'm a fencer

I'm a guitar player

I'm engineer

"Andrés is a good dad"  - My daughter

so.. who/how is he?

"Andrés is father from this school"  - My daughter's school

"Andrés has RUN xyz"  - National Registry

"RUN xyz has no debt here"  - My Bank

"@ajunge_m is very unpopular"  - Twitter

"andres.junge@consensys.net travels a lot"  - Google / Gmail

"(someone) is (something)"

- (someone else)

"(subject) is (claim)"

- (issuer)

Attestation

"(id-1) is (claim)"

- (id-2)

Attestation

{
    "sub": id-1,
    "iss": id-2,
    "claim": {
        ...
    }
    "exp": 1541687297,
    "nbf": 1541667297
}

signature( key:id-2 )

Attestation

identifiers

Name

Name + Village

Name + Family

Name + Family + Country

Number

System + Number

System + Any character secuence

RUT: xy-z

twitter: @ajunge_m

Pasaport: Chile: xy-z

email: andres.junge@consensys.net

Sovereignty

Ownership

Autonomy

of the identifier?

Control

RUT: xy-z

twitter: @ajunge_m

Pasaport: Chile: xy-z

email: andres.junge@consensys.net

Private Key

Public Key

 

for Identity

Public Key Infrastructure :: PKI

Pretty Good Privacy :: PGP

Control over my key

Control over my identity

Blockchain anchor

Control Keys

Signing Keys

Decentralized Identity Foundation

https://identity.foundation/

https://w3c-ccg.github.io/did-spec/

https://www.w3.org/community/credentials/

Decentralized Identifier - DID

 DID - Doc

resolves

did:ethr:0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736
{
  "id": "did:ethr:0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736",
  "authentication": {
    "type": "Secp256k1SignatureAuthentication2018",
    "publicKey": [
      "did:ethr:0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736#owner"
    ]
  },
  "publicKey": [
    {
      "id": "did:ethr:0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736#owner",
      "type": "Secp256k1VerificationKey2018",
      "ethereumAddress": "0x3b0bc51ab9de1e5b7b6e34e5b960285805c41736",
      "owner": "did:ethr:0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736"
    }
  ],
  "@context": "https://w3id.org/did/v1"
}

resolves

Attestation

{
    "sub": did:sov:WRfXPg8dantKVubE3HX8pw,
    "iss": did:ethr:0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736,
    "claim": {
        ...
    }
    "exp": 1541687297,
    "nbf": 1541667297
}

signature( 0x3b0BC51Ab9De1e5B7B6E34E5b960285805C41736 )

https://uport.me

Self Sovereign Identity Open Platform

Mobile App

Libraries (js)

Specs

https://github.com/uport-project/

Mobile App

Libraries

uport-connect

uport-credentials

did-jwt

Libraries

$ create-react-app uport-madrid
Creating a new React app in /tmp/uport-madrid.

[...]

Happy hacking!

$ cd uport-madrid
$ npm i --save uport-connect

[...]

+ uport-connect@1.1.4

[...]

$ yarn start
src/App.js
[...]

import { Connect } from 'uport-connect';

class App extends Component {
  
  componentDidMount() {
    const uport = new Connect('Mi dApp');
    
    uport.requestDisclosure()

    uport.onResponse('disclosureReq').then(res => {
        console.log(res);
    })
  }

[...]
requestToken

https://id.uport.me/req/<jwt.token>?callback_type=post

{
  "iat": 1551829068,
  "exp": 1551829668,
  "callback": "https://api.uport.space/chasqui/topic/N3j13hg-9aSfxxeRCE6HGA",
  "vc": [
    "/ipfs/QmXPKEa9prnpaWwG39dfYrTwqqjTz4vtV6UxNSqb857ZUG"
  ],
  "act": "none",
  "type": "shareReq",
  "iss": "did:ethr:0x8d5d3ebfe9c350422c655c5869f0a09bb4743bd3"
}

https://github.com/uport-project/specs

"vc"

https://ipfs.infura.io/ipfs/Qm....

{
  "iat": 1551829062,
  "sub": "did:ethr:0x8d5d3ebfe9c350422c655c5869f0a09bb4743bd3",
  "claim": {
    "name": "Mi dApp",
    "url": "http://localhost:3000"
  },
  "iss": "did:ethr:0x8d5d3ebfe9c350422c655c5869f0a09bb4743bd3"
}

https://jwt.io

responseToken

access_token

{
  "iat": 1551829120,
  "exp": 1551915520,
  "aud": "did:ethr:0x8d5d3ebfe9c350422c655c5869f0a09bb4743bd3",
  "type": "shareResp",
  "own": {},
  "req": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NTE4MjkwNjgsImV4cCI6MTU1MTgyOTY2OCwiY2FsbGJhY2siOiJodHRwczovL2FwaS51cG9ydC5zcGFjZS9jaGFzcXVpL3RvcGljL04zajEzaGctOWFTZnh4ZVJDRTZIR0EiLCJ2YyI6WyIvaXBmcy9RbVhQS0VhOXBybnBhV3dHMzlkZllyVHdxcWpUejR2dFY2VXhOU3FiODU3WlVHIl0sImFjdCI6Im5vbmUiLCJ0eXBlIjoic2hhcmVSZXEiLCJpc3MiOiJkaWQ6ZXRocjoweDhkNWQzZWJmZTljMzUwNDIyYzY1NWM1ODY5ZjBhMDliYjQ3NDNiZDMifQ.rafOEQRNvlmSHDuU6USF-OSnnzPpmTPcojmpRvzJkCKAb0A_U77-w-G54ouAH3lcL6t87aseW2yH401z_I-NOQE",
  "iss": "did:ethr:0xe3349bf29188b2ddec5ece151e2ce30959fa1715"
}

https://jwt.io

disclosure response
{
	"id": "disclosureReq",
	"payload": {
		"did": "did:ethr:0xe3349bf29188b2ddec5ece151e2ce30959fa1715"
	}
}
src/App.js
    componentDidMount() {

        const uport = new Connect('Mi dApp');

	const reqObj = { requested: ['name'],
	                  notifications: true }

	uport.requestDisclosure(reqObj)

	uport.onResponse('disclosureReq').then(res => {
	  console.log(res);
	})
    }
disclosure response
{
	"id": "disclosureReq",
	"payload": {
		"did": "did:ethr:0xe3349bf29188b2ddec5ece151e2ce30959fa1715",
		"boxPub": "Szu8qoO4aha8zI33t5fTkWaBurmyoyz/rK4L/K4VJnk=",
		"name": "Andrés Junge",
		"pushToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NTE4MzAzODgsImV4cCI6MTU1MzEyNjM4OCwiYXVkIjoiZGlkOmV0aHI6MHg4ZDVkM2ViZmU5YzM1MDQyMmM2NTVjNTg2OWYwYTA5YmI0NzQzYmQzIiwidHlwZSI6Im5vdGlmaWNhdGlvbnMiLCJ2YWx1ZSI6ImFybjphd3M6c25zOnVzLXdlc3QtMjoxMTMxOTYyMTY1NTg6ZW5kcG9pbnQvR0NNL3VQb3J0LzZkZDQ3YzBmLThlYWEtMzAzZi1hOGY2LTJmMmExZTNiMzk2NiIsImlzcyI6ImRpZDpldGhyOjB4ZTMzNDliZjI5MTg4YjJkZGVjNWVjZTE1MWUyY2UzMDk1OWZhMTcxNSJ9.zs1RvGYcoUuEkVvNgI8pPNPbl2qPkDllQ8yrblm8txeMVAQaRgjnooMG7XPhg6N4npHI8lj7_VgqWCgA1LC-LQA",
		"publicEncKey": "Szu8qoO4aha8zI33t5fTkWaBurmyoyz/rK4L/K4VJnk="
	}
}
src/App.js
  componentDidMount() {
    const uport = new Connect('Mi dApp');

    const reqObj = { requested: ['name'],	
	                  notifications: true }
	
	uport.requestDisclosure(reqObj)

	uport.onResponse('disclosureReq').then(res => {
	  return fetch('http://localhost:3001/?did='+res.payload.did);
	}).then((resp)=>{
	  return(resp.text());
	}).then((att)=>{
		uport.send("https://id.uport.me/req/"+att, "att")

		uport.onResponse("att").then(payload => {
			console.log(payload)
		})
	})

  }
server.js
const express = require('express')
const cors = require('cors')
const { Credentials }  = require('uport-credentials');

const app = express()
const port = 3001

const credentials = new Credentials({ 
	did: 'did:ethr:0x98015e7de5f0a766def2e67b64ac2fd7b7283c14',
  	privateKey: '22f86e734831a41281267ffefdc873eded6db1856783110286bd70ccc6b4894d' 
})

app.use(cors())

app.get('/', (req, res) => {
	credentials.createVerification({
	  sub: req.query.did, 
	  claim: { "uport-level": 8}
	}).then(attestation => {
		console.log(attestation)
		res.send(attestation)
	})
})

app.listen(port, () => console.log(`Listening on port ${port}!`))
create-identity.js
const { Credentials }  = require('uport-credentials');
console.log(Credentials.createIdentity())
Attestation
{
  "iat": 1551836909,
  "sub": "did:ethr:0xdef99e0d6789d5f81a17c9c50108fd10b938d2ab",
  "claim": {
    "uport-level": 8
  },
  "iss": "did:ethr:0x98015e7de5f0a766def2e67b64ac2fd7b7283c14"
}

https://jwt.io

App.js
requestSignature() {
  	const unsignedClaim = {
	    "dapp-awesomeness": 10000
	}
	
	const sub="did:ethr:0x98015e7de5f0a766def2e67b64ac2fd7b7283c14";

	uport.requestVerificationSignature(unsignedClaim,{sub: sub})

	uport.onResponse('verSigReq').then(res => {
	  const signedClaim = res.payload
	  console.log(signedClaim);
	})
}


render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <button onClick={ this.requestSignature }> Ask for signature.</button>
        </header>
      </div>
    );
  }
Attestation (signed by user)
{
  "iat": 1551838573,
  "exp": 1551924973,
  "sub": "did:ethr:0x98015e7de5f0a766def2e67b64ac2fd7b7283c14",
  "claim": {
    "dapp-awesomeness": 10000
  },
  "iss": "did:ethr:0xdef99e0d6789d5f81a17c9c50108fd10b938d2ab"
}

https://jwt.io

App.js
requestTxSignature() {
	const txObject = {
           to: '0xc3245e75d3ecd1e81a9bfb6558b6dafe71e9f347',
           value: '0.1',
           fn: "setStatus(string 'hello', bytes32 '0xc3245e75d3ecd1e81a9bfb6558b6dafe71e9f347')",
         }

	uport.createTxRequest(txObject)

	uport.onResponse('txSigReq').then(res => {
	  const txHash = res.payload
	  console.log(txHash);
	})
}


render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <button onClick={ this.requestTxSignature }> Ask for tx signature.</button>
        </header>
      </div>
    );
  }

Recap

* DID

* DID resolves to DID Doc

* uPort - Selective Disclosure

* uPort - Signing requests

* DID Keys sign Attestations about other DIDs

* Attestations conform an identity

* User in control of the identity. Sovereign.

uPort WorkShop

By Andres Junge

uPort WorkShop

Madrid Hackhathon 2019

  • 480