---
# System prepended metadata

title: Sign-in with Ethereum

---

# 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)