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