# Sign-in with Ethereum ## Links - [Sign-in with Ethereum RFP](https://notes.ethereum.org/@djrtwo/sign-in-with-ethereum-RFP) - [Veramo response](https://docs.google.com/document/d/155IX32AZi0Kyxj29f9k745_V5ZcuXs86xRUFIVAm5m8/edit) - [Self-Issued OpenID Provider V2, draft 02](https://openid.bitbucket.io/connect/openid-connect-self-issued-v2-1_0.html) - [URL Based Discovery for Trust Frameworks using SIOP](https://hackmd.io/@quartzjer/SIOP_Discovery_Trust_Framework) ## Why do we need a sign-in? - To personalize UI/UX - Settings - Filter backend data - To track users ## Sequence diagrams - Open website - Login - Get the list of my articles - Post a new article ### Simple web2 flow ```mermaid sequenceDiagram rect rgba(0, 255, 0, .1) Browser->>+Service: GET / Service->>+Sessions: Create session Sessions-->>-Service: SessionId: 10 Service-->>-Browser: HTML + Cookie - SessionId: 10 end Browser->>+Service: POST /login username, password, sessionId: 10 Service->>+Users: Check username+password Users-->>-Service: UserId: 5 Service->>+Sessions: Update: SessionId: 10, UserId: 5 Sessions-->>-Service: success Service-->>-Browser: success rect rgba(0, 0, 255, .1) Browser->>+Service: GET /my-articles, sessionId: 10 Service->>+Sessions: Get user - sessionId: 10 Sessions-->>-Service: UserId: 5 Service->>+Articles: Get - UserId: 5 Articles-->>-Service: articles Service-->>-Browser: articles Browser->>+Service: POST /article, sessionId: 10, body: foo Service->>+Sessions: Get user - sessionId: 10 Sessions-->>-Service: UserId: 5 Service->>+Articles: Save - UserId: 5, body: foo Articles-->>-Service: ArticleId: 3 Service-->>-Browser: Location /articles/3 end ``` ### Oauth web2 flow ```mermaid sequenceDiagram rect rgba(0, 255, 0, .1) Browser->>+Service: GET / Service->>+Sessions: Create session Sessions-->>-Service: SessionId: 10 Service-->>-Browser: HTML + Cookie - SessionId: 10 end Browser->>+Service: GET /login Service-->>-Browser: Location: google.com/auth Browser->>+Google: POST /login username, password Google-->>-Browser: Location: service/callback, token: abc Browser->>+Service: GET: service/callback, token: abc, sessionId: 10 Service->>+Google: Get User - token: abc Google->>-Service: UserId: 5 Service->>+Sessions: Update SessionId: 10, UserId: 5 Sessions-->>-Service: success Service-->>-Browser: HTML success rect rgba(0, 0, 255, .1) Browser->>+Service: GET /my-articles, sessionId: 10 Service->>+Sessions: Get user - sessionId: 10 Sessions-->>-Service: UserId: 5 Service->>+Articles: Get - UserId: 5 Articles-->>-Service: articles Service-->>-Browser: articles Browser->>+Service: POST /article, sessionId: 10, body: foo Service->>+Sessions: Get user - sessionId: 10 Sessions-->>-Service: UserId: 5 Service->>+Articles: Save - UserId: 5, body: foo Articles-->>-Service: ArticleId: 3 Service-->>-Browser: Location /articles/3 end ``` ### Web2 + DIDAuth flow ```mermaid sequenceDiagram rect rgba(0, 255, 0, .1) Browser->>+Service: GET / Service->>+Sessions: Create session Sessions-->>-Service: SessionId: 10 Service-->>-Browser: HTML + Cookie - SessionId: 10 end Browser->>+Service: GET /login sessionId: 10 Service->>+Nonces: Get new nonce Nonces-->>-Service: abc123 Service->>+Sessions: Update session: 10, nonce: abc123 Sessions-->>-Service: success Service->>Service: generate SIOP request Service-->>-Browser: HTML + siop=' openid://nonce=abc123&cb=...'' rect rgba(255, 0, 0, .1) Browser->>+OP: GET /login?siop=urlEncode(siop) OP-->>-Browser: Location: cb?token=xyz end Browser->>+Service: GET cb?token=xyz, sessionId: 10 Service->>+Sessions: Get nonce - sessionId: 10 Sessions-->>-Service: abc123 Service->>Service: Verify token with nonce Service->>+Nonces: Invalidate nonce: abc123 Nonces-->>-Service: success Service->>+Sessions: Update SessionId: 10, UserId: did:ens:alice.eth Sessions-->>-Service: success Service-->>-Browser: HTML success rect rgba(0, 0, 255, .1) Browser->>+Service: GET /my-articles, sessionId: 10 Service->>+Sessions: Get user - sessionId: 10 Sessions-->>-Service: UserId: did:ens:alice.eth Service->>+Articles: Get - UserId: did:ens:alice.eth Articles-->>-Service: articles Service-->>-Browser: articles Browser->>+Service: POST /article, sessionId: 10, body: foo Service->>+Sessions: Get user - sessionId: 10 Sessions-->>-Service: UserId: did:ens:alice.eth Service->>+Articles: Save - UserId: did:ens:alice.eth, body: foo Articles-->>-Service: ArticleId: 3 Service-->>-Browser: Location /articles/3 end ``` #### OP flow ```mermaid sequenceDiagram Browser->>+OPServer: GET /login?siop=... OPServer-->>-Browser: HTML + decoded siop Browser->>+AppFlow: nonce, domain, web3 AppFlow-->>-Browser: {did, claims, proof} Browser->>OPServer: POST /sign-token {siop, did, claims, proof} OPServer->>OPServer: sign JWT ``` #### App flow ```mermaid sequenceDiagram app->>+SDK: signIn(nonce, domain, web3) SDK->>+web3Provider: connect web3Provider-->>-SDK: account = '0x00...42' SDK->>ENS: getName('0x00...42') alt success ENS-->>SDK: alice.eth note right of SDK: did = 'did:ens:alice.eth' SDK->>ENS: getText('picture') ENS-->>SDK: 'https://example.com/avatar.png' note over ENS,SDK: claims['picture'] = 'https://example.com/avatar.png' else there is no ENS domain ENS-->>SDK: false note right of SDK: did = 'did:ethr:0x00...42' end SDK->>+web3Provider: eth_signTypedData note over SDK, web3Provider: did, nonce, domain, claims web3Provider-->>-SDK: signature SDK->>SDK: validate signature with eth account and nonce SDK-->>-app: {did, claims, proof} ``` #### ENS Web2 flow using SIOPv2 (simplified version) ```mermaid sequenceDiagram note over Browser: sign-in process starts here Browser->>Backend: get sign-in page Backend->>BackendSDK: sdk.createSignInRequest(<requested-claims>) BackendSDK-->>Backend: <SIOPv2-request> Backend-->>Browser: sign-in page, <SIOPv2-request> Browser->>FrontendSDK: sdk.login(<SIOPv2-request>) FrontendSDK->>Wallet: web3.connect Wallet-->>FrontendSDK: <ETH-account> FrontendSDK->>ENS: ens.resolve(<ETH-account>) ENS-->>FrontendSDK: <ENS-name> FrontendSDK->>ENS: ens.fetchClaims(<ENS-name>) ENS-->>FrontendSDK: <claims> note over Browser: <ENS-name> to DID defaults to<br/> simple secp256k1 auth/assertion key DID Doc<br/> if no DID/DID Doc text record was found FrontendSDK->>FrontendSDK: sdk.discoverDid(<ENS-name>): <did:ens> FrontendSDK->>FrontendSDK: sdk.createDataToBeSigned(<did:ens>, <claims>, <siop-nonce>, <siop-client>) : <EIP712-data> FrontendSDK->>Wallet: web3.signTypedData(<EIP712-data>) Wallet-->>FrontendSDK: <EthereumEip712Signature2021> FrontendSDK->>FrontendSDK: sdk.packToken(<EIP712-data>, <EthereumEip712Signature2021>) : <id_token> FrontendSDK-->>Browser: <id_token> Browser->>Backend: submit <id_token> Backend->>BackendSDK: sdk.verifyToken(<id_token>) BackendSDK-->>Backend: <verified-user-info> Backend->>Backend: createSession() : <session> Backend-->>Browser: set <session>, <verified-user-info> ``` #### Proposal ##### Minimum Web3 Flow ```mermaid sequenceDiagram Frontend->>SDK: login SDK->>API: GET /auth/nonce API-->>SDK: nonce SDK->>Wallet: connect Wallet-->>SDK: eth account(s) SDK->>Wallet: personal_sign Wallet-->>SDK: signature SDK->>API: POST /auth/token (signature) API->>API: ecrecover, verify signature API->>API: did:ens/eth address to DID API->>API: sign JWT (HS256, publicAddress=0xabb, <br/> username=vitalik.eth, did=did:ethr:0xabb | did:ens:vitalik.eth) API-->>SDK: JWT SDK-->>Frontend: JWT Frontend->>API: POST /other/endpoint with JWT API-->>Frontend: ok ``` ##### Better Web3 Flow ```mermaid sequenceDiagram Frontend->>SDK: login SDK->>API: GET /auth/nonce API-->>SDK: nonce SDK->>Wallet: connect Wallet-->>SDK: eth account(s) SDK->>Wallet: eip2844, did_authenticate / did_createJWS(ethaccount) Wallet-->>SDK: JWS with a DID SDK->>API: POST /auth/token (signature) API->>API: ecrecover, verify signature API->>API: ens/eth address to DID API->>API: sign JWT (HS256, publicAddress=0xabb, <br/> username=vitalik.eth, did=did:ethr:0xabb | did:ens:vitalik.eth) API-->>SDK: JWT SDK-->>Frontend: JWT Frontend->>API: POST /other/endpoint with JWT API-->>Frontend: ok ``` #### Questions - The user needs to select which DID to use for the sign-in. How do we construct this list of DIDs? - did:ethr:0x1234 - did:ens:simonas.eth - did:nft:0x0000042:69 [Alternative SIOP diagrams](/V8sz7CVhSkO12nZBvNQtnw)