Skip to main content

Wallet Authentication

User Flow

User visits a new website that requires authentication from wallet.

  1. Website displays Pairing qrcode or deep link
  2. User scans qrcode or redirects to wallet
  3. User approves prompt for auth in wallet
  4. User returns to website after prompt success
  5. Website is now authenticated with signed message

User returns to a previously visited website before authentication expiry

  1. Website checks if user is authenticated from local storage
  2. Website is now authenticated with signed message

User returns to a previously visited website after authentication expiry

  1. Website checks if user is authenticated from local storage
  2. Website generates new keypair and derives a new response topic from it
  3. Website sends new request to previously paired wallet, using known pairing topic, but subscribes to new response topic
  4. User is prompted/redirected to wallet
  5. User approves prompt for auth in wallet, wallet responds on the new response topic
  6. User returns to website after prompt success
  7. Website is now authenticated with signed message

Request Protocol

Prerequisites

A and B are required to establish pairing before proceeding to wallet authentication flow.

Protocol

A generates keyPair X and generates response topic.

Response topic is the hash of publicKey X.

A will construct an authentication request.

A publishes request on A-B pairing.

A subscribes to messages on response topic.

B receives request on A-B pairing.

B constructs message to be signed from request and signs it.

B generates keyPair Y and generates shared symKey R.

B encrypts response with symKey R as type 1 envelope.

B sends response on response topic.

A receives response and validates signature.

If signature is valid, then user is authenticated.

Capabilities

Applications can request consent from users to perform actions on their behalf. These actions are included in the authentication request in the form of ReCaps, a compact encoding for authorization statements. WalletConnect's implementation follows closely the ERC-5573 specs. ReCaps are also used to include additional fine-grained authorization information along with the WalletConnect's handshake that establishes a Sign session.

Overview

ReCaps capabilities are included in the auth request in the resources array. They are prefixed with urn:recap: and are base64 encoded. Authentication message with recaps would look like

http://example.com wants you to sign in with your Ethereum account:
0x3613699A6c5D8BC97a08805876c8005543125F09

I further authorize the stated URI to perform the following actions on my behalf: (1) 'request': 'eth_signTypedData_v4', 'personal_sign' for 'eip155'.

URI: https://example.com
Version: 1
Chain ID: 1
Nonce: 1
Issued At: 2024-02-19T09:29:21.394Z
Resources:
- urn:recap:eyJhdHQiOnsiZWlwMTU1Ijp7InJlcXVlc3QvZXRoX3NpZ25UeXBlZERhdGFfdjQiOlt7fV0sInJlcXVlc3QvcGVyc29uYWxfc2lnbiI6W3t9XX19fQ==

The recap in the message

- urn:recap:eyJhdHQiOnsiZWlwMTU1Ijp7InJlcXVlc3QvZXRoX3NpZ25UeXBlZERhdGFfdjQiOlt7fV0sInJlcXVlc3QvcGVyc29uYWxfc2lnbiI6W3t9XX19fQ==

after removing the prefix (urn:recap:), Base64-decoding the string would result in the JSON object:

{
"att":{
"eip155":{
"request/eth_signTypedData_v4":[{}],
"request/personal_sign":[{}]
}
}
}

This ReCap Object is generated by the requesting application and is used to build the statement

I further authorize the stated URI to perform the following actions on my behalf: (1) 'request': 'eth_signTypedData_v4', 'personal_sign' for 'eip155'.

Any data following above format & ERC-5573 specs can be encoded and requested as part of Authentication request, even multiple recaps.

http://example.com wants you to sign in with your Ethereum account:
0x3613699A6c5D8BC97a08805876c8005543125F09

I further authorize the stated URI to perform the following actions on my behalf: (1) 'request': 'eth_signTypedData_v4', 'personal_sign' for 'eip155'. (2) 'push': 'messages', 'notification' for 'eip155'. (3) 'receive': 'messages', 'notification' for 'eip155'.

URI: https://example.com
Version: 1
Chain ID: 1
Nonce: 1
Issued At: 2024-02-19T09:29:21.394Z
Resources:
- urn:recap:eyJhdHQiOnsiZWlwMTU1Ijp7InJlcXVlc3QvZXRoX3NpZ25UeXBlZERhdGFfdjQiOlt7fV0sInJlcXVlc3QvcGVyc29uYWxfc2lnbiI6W3t9XX19fQ==
- https://example.com/storage/0x3613699A6c5D8BC97a08805876c8005543125F09
- urn:recap:eyJhdHQiOnsiZWlwMTU1Ijp7InB1c2gvbWVzc2FnZXMiOlt7fV0sInB1c2gvbm90aWZpY2F0aW9uIjpbe31dfX19
- urn:recap:eyJhdHQiOnsiZWlwMTU1Ijp7InJlY2VpdmUvbWVzc2FnZXMiOlt7fV0sInJlY2VpdmUvbm90aWZpY2F0aW9uIjpbe31dfX19

Authenticated sessions

As mentioned above, applications utilize ReCaps to request additional permissions or capabilities from users, beyond what the basic capabilities (chains, accounts, methods) that get negotiated in a WalletConnect connection between application and a wallet.

Each authentication request includes an array of requested chains. Users can choose to approve all or part of the chains depending on their wallet support.

Scenario A

Only subset of the requested chains is supported by the wallet e.g.

requested: ['eip155:1', 'eip155:2']
supported: ['eip155:1']

Only eip155:1 is to be approved for the session. Then, the recap containing the methods requested is to be updated as follows

{
"att":{
"eip155":{
"request/eth_signTypedData_v4":[{
chains: ['eip155:1']
}],
"request/personal_sign":[{
chains: ['eip155:1']
}]
}
}
}

After the recap is updated, we can base64 encode it, add urn:recap: prefix and replace the old one in the resources array. Now the message is ready for users approval & signing.

This signals that the wallet supports chain eip155:1, is authenticated and can receive requests for that chain. The application (requesting authentication) should receive ONE signed CACAO.

Scenario B

When multiple chains are supported wants to authenticate all of them

requested: ['eip155:1', 'eip155:2', 'eip155:3']
supported: ['eip155:1', 'eip155:2', 'eip155:3']

the wallet should update the recap and list all of their supported chains

{
"att":{
"eip155":{
"request/eth_signTypedData_v4":[{
chains: ['eip155:1', 'eip155:2', 'eip155:3']
}],
"request/personal_sign":[{
chains: ['eip155:1', 'eip155:2', 'eip155:3']
}]
}
}
}

Now the wallet can sign the messages (one for each chain) and respond to the request.

Scenario C

When apps receive single signed CACAO that includes multiple chains in its recaps, it can be considered approval for establishing a session and sending requests to all included chains but authentication is guaranteed only for the signed chain.

Now, the wallet & the application, after it receives the signed CACAO(s) response can establish authenticated session with the same chains, methods & accounts.