diff --git a/content/00.zksync-era/30.unique-features/30.zksync-sso/28.account-recovery.md b/content/00.zksync-era/30.unique-features/30.zksync-sso/28.account-recovery.md index 9208aa76..56f0dbc3 100644 --- a/content/00.zksync-era/30.unique-features/30.zksync-sso/28.account-recovery.md +++ b/content/00.zksync-era/30.unique-features/30.zksync-sso/28.account-recovery.md @@ -62,8 +62,8 @@ shows how users are alerted of pending recoveries during normal SSO login and ca ### Module Implementation -The solution centers on a [new erc7579 validator module](https://erc7579.com/modules) called `GuardianRecoveryValidator`. This guide illustrates -how to perform different guardian recovery actions with this module: +The solution centers on a new [ERC7579 inspired validator module](https://docs.zksync.io/zksync-era/unique-features/zksync-sso/account-modules) +called `GuardianRecoveryValidator`. This guide illustrates how to perform different guardian recovery actions with this module: #### Adding & verifying a Guardian @@ -132,6 +132,173 @@ A pending recovery can be discarded using `discardRecovery`, which: 1. Removes the recovery request from storage. 2. Emits a **`RecoveryDiscarded`** event for traceability. +## Account Recovery with Google + +The solution allows users to link **a Google account as a recovery method** to their SSO account, +and later use that Google account to **recover access to their SSO account** without revealing +their email or any information that would expose their identity. + +The guide below provides information about the linking and recovery process, with further details about these two main components +in the solution: + +- An [ERC7579 inspired validator module](https://docs.zksync.io/zksync-era/unique-features/zksync-sso/account-modules) (`OidcRecoveryValidator`) + is in charge of managing the recovery data of every SSO account. +- A **ZK circuit** is used to prove the ownership of an Google account without revealing the account information. + +### Main flows high-level description + +The process consists of two main phases: + +1. **Google Account Linking:** The user links their Google account to their SSO account with the `OidcRecoveryValidator`. +2. **Account Recovery with Google:** The user shows proof of owning a `JWT` issued to the same Google account + from an auxiliary account and adds a new passkey to their SSO account. + +::callout{icon="i-heroicons-light-bulb"} +Throughout this documentation, you'll encounter the term OIDC. Open ID Connect is **an identity authentication protocol** +built on top of OAuth 2.0 to create a standard way of authenticating and authorizing users when they access digital services. +For more information, please refer to the [OIDC documentation](https://openid.net/developers/how-connect-works/). +:: + +#### **Google account linking to the SSO account** + +To use their Google Account for recovery, the user needs to link it to their SSO account. For this, they will request a `JWT`, +extract the necessary data, combine it with the salt, and create a hash of these elements. +Finally, this hash will be registered in the `OidcRecoveryValidator`. + +![Google Account Linking](/images/zksync-sso/account-recovery/oidcLinking.svg) + +**OIDC Digest** + +The JWT has 3 attributes that together identify a Google account: `iss` (issuer), `aud` (audience), and `sub` (subject). +Hashing the 3 of them generates a way to identify the user. + +Saving a hash of those 3 is a way to save a reference to the Google account. + +To provide extra security, a `salt` is added. This salt is managed by a different entity and works as a second factor of security. + +Finally, the digest is calculated as follows: + +`PoseidonHash(iss || aud || sub || salt)` + +#### **Step 2: Present ownership proof for recovery** + +**When users lose access to their account**, they must interact with the `OidcRecoveryValidator` through an auxiliary account +to validate that they have ownership of the account to be recovered. + +Since this is a recovery process, users won't have access to their SSO account when presenting the proof. +An auxiliary account with enough funds to cover the transaction cost will have to be used to submit the proof. + +OIDC allows users to populate the `nonce` field with custom data. This field contains the recovery data within the `JWT`, +enabling the circuit to verify that the `JWT` was specifically generated for this recovery. + +::callout{icon="i-heroicons-light-bulb"} +Through the ZK proof, the system verifies that the Google Account owner is authorizing the SSO account recovery. +Users generate this proof locally on their device, while the contract supplies the public arguments for verification. +:: + +After completing this process, users can add a new passkey to their SSO account, successfully recovering access to it. + +![Google Account Recovery](/images/zksync-sso/account-recovery/oidcRecovery.svg) + +### Module Implementation + +The [**`OidcRecoveryValidator`**](https://github.com/matter-labs/zksync-sso-clave-contracts/blob/main/src/validators/OidcRecoveryValidator.sol) +is an [ERC7579 inspired validator module](https://docs.zksync.io/zksync-era/unique-features/zksync-sso/account-modules) +that enables zero-knowledge-based account recovery via OpenID Connect (OIDC) identity assertions. It enables user to add a new passkey +if they can prove control over an OIDC identity (e.g., their Google account) previously linked to their SSO account. + +#### **Adding & removing linking to OIDC identities** + +The following functions manage the linking and unlinking of OIDC identities: + +**Account Linking** + +The function `addOidcAccount()` links an OIDC identity (`oidcDigest`, `iss`) to a new or existing SSO account. +As a restriction, the `oidcDigest` must not be registered to another account. + +- Emits: `OidcAccountUpdated`. + +**Remove Linking** + +The function `deleteOidcAccount()` (**and internal `_deleteOidcAccount`)** fully cleans OIDC data, +both from the SSO account and the digest mapping. + +- Emits: `OidcAccountDeleted` + +#### **Recovery process** + +The following functions play a crucial role in the recovery process: + +**Initiating Recovery** + +`startRecovery()` is called with a zk proof and the hash of the new passkey. It checks the proof by calling the ZK verifier. +If the ZK proof verification fails, this method reverts. + +- Emits: `RecoveryStarted` + +**Completing Recovery (Validating transaction & updating passkey)** + +`validateTransaction()` validates a transaction that aims to add a new passkey after a successful `startRecovery()`. + +- If all checks pass, it resets the recovery state and returns `true`, authorizing the transaction. Otherwise, it returns `false`. + +**Cancelling Recovery** + +Users can opt to cancel an active recovery at any time before completion, via `cancelRecovery()`. + +- Emits: `RecoveryCancelled`. + +### Circuit Implementation + +::callout{icon="i-heroicons-light-bulb"} +The circuit is implemented in **Circom** and leverages code from [`circomlib`](https://github.com/iden3/circomlib) and [`zkemail`](https://github.com/zkemail). +:: + +The circuit performs **two key validations:** + +- Prove that the user owns a valid JWT signed by Google and issued for the specific Google account. +- Prove that the owner of the JWT had the intention of performing the transaction. + +To do this, it **does 4 main operations:** + +1. Validate the JWT. This is done by performing the standard JWT validation using RS256 with the Google public key. +2. Parse and extract important data from the JWT: `iss`, `sub`, `aud`, and `nonce` +3. Recreate and validate the OIDC digest. +4. Recreate and validate the content of the nonce. + +![OidcCircuit](/images/zksync-sso/account-recovery/oidcCircuit.png) + +For more information, please refer to the [Circuit repository](https://github.com/Moonsong-Labs/zksync-social-login-circuit/). + +#### **Inputs** + +The circuit's inputs fall into three main categories: + +**Key elements for validation** + +The circuit requires **4 primary inputs, which enable its core validation functions**: + +1. **The `JWT`** (private): This is the raw JWT, as sent by Google. +2. **Google's public key** (public). +3. **The expected digest** (public, more on this later): `PoseidonHash(sub || aud || iss || salt)` +4. **The expected content of the nonce** (public): Set by the user and then signed by Google. + +**Privacy & ownership** + +Two additional inputs are essential for maintaining privacy: + +- **Blinding factor** (private): Random value used to avoid revealing the nonce defined by the user. +- **Salt** (private): Deterministic value. Used to create a second factor of security and avoid Google being + the only custodian of the wallet. + +**Optimization & other elements** + +Finally, there are several additional inputs used for optimization purposes, such as the indices of all important elements within the JWT. + +#### Outputs + +Rather than producing an output value, the circuit acts as a validator - it fails if any of the required validations are unsuccessful. + *More account recovery options are coming soon.*