# Sign in with Google to your Identity Contract (for fun and profit)

**URL:** <https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631>\
**Category:** Showcase\
**Created:** [October 26, 2019, 6:17pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631 "2019-10-26T18:17:25Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![spalladino](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/spalladino/32/22_2.png) [@spalladino](https://forum.openzeppelin.com/u/spalladino)\
**Post date:** [October 26, 2019, 6:17pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/1 "2019-10-26T18:17:26Z")

</div>

There are [many](https://www.toptal.com/ethereum/one-click-login-flows-a-metamask-tutorial) [guidelines](https://hackernoon.com/never-use-passwords-again-with-ethereum-and-metamask-b61c7e409f0d) on using Ethereum's accounts for signing in to an application. This enables a _Sign In With Ethereum_ experience, that relies on the user signing an attestation of their identity with their private key, which is used to log them in to an app. This has the main benefit of decentralization over the traditional _Sign In With Google_, since we no longer depend on Google as a centralized identity provider.

However, some time ago, we wondered what would happen if we flipped this around. In other words, instead of using Ethereum as a replacement to Google to sign in to an app, what if we could use Google to sign in to Ethereum? As a concrete use case, could we **support recovery of an Ethereum identity contract using Google Sign In** , without adding any extra trusted components? Turns out [we could](https://identity-recovery-demo.openzeppelin.com/).

## Identity contracts & recovery

Identity contracts, also known as smart wallets, are a pattern for moving the user's identity from their local keys to the blockchain itself. For all practical purposes, the user identity is no longer an externally owned, but a smart contract itself. This allows a user to have multiple devices, each of them with its own private key, which are registered as operators of a single identity contract. This contract's address then holds the users' funds and represents them online, and is used to interact with any other Ethereum protocols. [Authereum](https://authereum.org/), [Gnosis Safe](https://safe.gnosis.io/), [Universal Login](https://universallogin.io/), and [Argent](https://www.argent.xyz/) (to cite a few examples) implement this pattern.

Having access from multiple devices ensures that, if you lose one, you can still access your online identity from a different one. However, if you lose access to all of them, you still need some recovery option baked-in, since _forgot my password_ does not work in a decentralized world. One of the most popular options to solve this is problem is _social recovery_, where you designate a set of friends to grant you access back to your identity should you get locked out.

With this scenario in mind, together with @frangio, we set out to build an experiment: given that most users already trust Google with their digital life, **could we add a _Google Recovery_ option, in which the user's identity in Google could be used to regain access to their identity contract?**

## How it looks like for a user

We built a [small client-side-only demo app](https://identity-recovery-demo.openzeppelin.com/) to showcase how this experience looks for the user. The user first signs in with Google to a page, in order to get their Google user ID. This ID is stored when deploying their identity contract, as well as the identifier of the application the user signed in to.

> **Note:** This application (which will be referred to as the _audience_ later) needs to be created once from the [Google Developer Console](https://console.developers.google.com/), specifying the domain where it'll be hosted.

 ![Screenshot%20from%202019-10-26%2013-08-06](https://us1.discourse-cdn.com/flex022/uploads/zeppelin/original/2X/1/1d6aa5d6b13a0ca12a46569335aa6461d18b888f.png)

Afterwards, if the user switches to a different Ethereum account, they can go through a _recover_ flow where they are asked to sign in with Google again and send a transaction to the identity contract from their new Ethereum account.

 ![Screenshot%20from%202019-10-26%2013-06-47](https://us1.discourse-cdn.com/flex022/uploads/zeppelin/original/2X/c/c63e1eb585423387afc31045a77c7a4609471691.png)

The authentication result is then sent to the identity contract, which recognizes the user ID validated by Google, and adds the new Ethereum account as owner of the identity contract. This allows a user to **regain access to their decentralized Ethereum identity with just a single transaction - and a Google Sign In**.

## How it works under the hood

We are using [Google Sign In for Websites](https://developers.google.com/identity/sign-in/web), which is a flow designed to work without a server. In this flow, the user is prompted to sign in to their Google account, and Google **returns a signed JSON Web Token ([JWT](https://jwt.io/)) with the user's identity**.

JWTs are composed of three sections, all base64-encoded: a header, a payload, and a signature. The header contains information such as the signer and the audience, while the payload contains the user information. The interesting thing here is that the JWT is compact enough that it can be **decoded and verified in a smart contract**.

In our project, all this magic happens in the [`recover` method](https://github.com/OpenZeppelin/solidity-jwt/blob/1bc6578cbaccd6d179f4892cd9ba76ffad99a65b/contracts/Identity.sol#L31-L55) of the sample Identity contract we have built.

```solidity
  function recover(string memory headerJson, string memory payloadJson, bytes memory signature) public {
    string memory headerBase64 = headerJson.encode();
    string memory payloadBase64 = payloadJson.encode();
    StringUtils.slice[] memory slices = new StringUtils.slice[](2);
    slices[0] = headerBase64.toSlice();
    slices[1] = payloadBase64.toSlice();
    string memory message = ".".toSlice().join(slices);
    string memory kid = parseHeader(headerJson);
    bytes memory exponent = getRsaExponent(kid);
    bytes memory modulus = getRsaModulus(kid);
    require(message.pkcs1Sha256VerifyStr(signature, exponent, modulus) == 0, "RSA signature check failed");

    (string memory aud, string memory nonce, string memory sub) = parseToken(payloadJson);
    
    require(aud.strCompare(audience) == 0 || true, "Audience does not match");
    require(sub.strCompare(subject) == 0, "Subject does not match");

    string memory senderBase64 = string(abi.encodePacked(msg.sender)).encode();
    require(senderBase64.strCompare(nonce) == 0, "Sender does not match nonce");

    if (!accounts[msg.sender]) {
      accounts[msg.sender] = true;
      accountsList.push(msg.sender);
    }
  }

```

This method verifies Google's signature to check the JWT is valid. It then checks that the `audience` (ie the app that requested the token) is the same as used when creating the identity contract, and then checks that the `subject` (ie the user) is the same as well. This requires base64 encoding and RSA verification, all done on-chain. As you can imagine, this process consumes a lot of gas; but recovery should not be a frequent operation. If everything is verified correctly, then the user's new Ethereum address is added to the identity contract.

However, we now have a missing piece: **how do we prevent someone from front-running the transaction, grab the JWT sent to the contract, and use it to gain access themselves?**

The solution we found here is tricking Google into signing the new Ethereum address as part of the JWT itself. And we are doing it by **setting the Ethereum address as the JWT's request nonce** , which in turn gets signed as part of the JWT itself, which we can then validate in the identity contract. A bit hacky, but works!

> **Note:** As you may have seen if you tried the demo, the nonce is never exposed to the user as they _Sign In With Google_ in the application, meaning that they could be inadvertently getting Google to sign a different Ethereum account if the app is malicious. This could even be done by any other application in which the user signs in with Google, which uses the JWT behind the scenes to gain access to the user's Ethereum Identity. We currently mitigate this by validating the audience (ie the Google app identifier) in the smart contract, so only the original app can recover access to the contract. This requires the user to trust this single app, which could be further mitigated by storing the page in IPFS to ensure its immutability after it was audited once.
> 
> However, this still requires trust on the owner of the Google Developer project, who may add new malicious domains and trick the users into signing in there, or even close the project removing the possibility of recovery. That in turn could be mitigated by having users could download the page and run it locally, configuring their own Google Developer project, though the user experience is far from ideal.

## A keys oracle

The last piece of the puzzle is how to get the public keys used by Google to sign the JWTs, since these are rotated frequently. These keys are advertised in [this URL](https://www.googleapis.com/oauth2/v3/certs), as indicated on [Google's OpenID configuration](https://accounts.google.com/.well-known/openid-configuration).

At the moment, we are storing these keys in a trusted [JWKS (JSON Web Key Set) contract](https://github.com/OpenZeppelin/solidity-jwt/blob/master/contracts/JWKS.sol) which keeps track of these keys. However, the owner of the contract (currently us) could inject a malicious public key, and use it to self sign fake JWTs, gaining access to all users' identity contracts. This makes this a contract a key piece of the infrastructure.

An oracle solution could be used to fill in this gap, such as [Chainlink](https://chain.link/) or [Provable](https://provable.xyz/). In particular, since the keys are advertised from a single URL endpoint, an [integration](https://docs.provable.xyz/#general-concepts-authenticity-proofs) with [TLSNotary](https://tlsnotary.org/) could be used here.

## FAQ

- _Can I try this out?_  
Sure! Head over to [https://identity-recovery-demo.openzeppelin.com/](https://identity-recovery-demo.openzeppelin.com/) on the Rinkeby network to test our demo. Note that the keys may have already been rotated, and updating them is a manual process - so if recovery fails, let us know! 🙏

- _Show me the code!_  
Ok, not an actual question, but we get the point. Everything's available on our [github](https://github.com/OpenZeppelin/solidity-jwt)! 📚

- _Can I use this in production?_  
Dear lord, no! There are many things to figure out still (such as trust on the google developer project, or the oracle for the signing keys), and the whole solution relies on the hack of using an ethereum account as a nonce - which is even undocumented ☠

- _Why did you do this?_  
Because we can! We were interested in seeing how far we could push Ethereum 🙂

- _Is that a good enough reason?_  
Sure! We are buidlers after all, right? 👷‍♂️ 👷‍♀️

---

<div class="post-metadata">

**Author:** ![pr0toshi](https://avatars.discourse-cdn.com/v4/letter/p/b5a626/32.png) [@pr0toshi](https://forum.openzeppelin.com/u/pr0toshi)\
**Post date:** [October 27, 2019, 9:51am UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/2 "2019-10-27T09:51:23Z")

</div>

How much gas would be used

---

<div class="post-metadata">

**Author:** ![bharathrao](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/bharathrao/32/1297_2.png) [@bharathrao](https://forum.openzeppelin.com/u/bharathrao)\
**Post date:** [October 27, 2019, 1:38pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/3 "2019-10-27T13:38:19Z")

</div>

Technically clever, but weaker in terms of security.

The scenario this scheme is trying to address is loss of keys. In the scheme presented, one would have to trust:

1. Google
2. Any current or past employee of Google who may have access
3. Governments who have authority over google
4. Operators of the smart contract.

This is addition to the trust that Google can protect its passwords. **Its a lot more secure to just AES encrypt your keys and storing your keys on google docs** if you don’t want to rely on your social recovery scheme. In general, adding a centralized party to a decentralized scheme creates more problems than it solves.

The ideal setup is to control all identities via a hardware wallet and memorize the seed phrase.

---

<div class="post-metadata">

**Author:** ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)\
**Post date:** [October 27, 2019, 11:24pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/4 "2019-10-27T23:24:15Z")

</div>

Hi @bharathrao,

Welcome to the community 👋

> [@spalladino](#):
>
> given that most users already trust Google with their digital life

I suspect that many future users of Ethereum will expect that there is a way to centrally recover access to their identity contract if they lose their keys. This has been their experience with their bank, their email and all their other non-web3 accounts.  
I am thinking about what my parents would do.

I can imagine identity contracts offering some from of centralized recovery as an option, that users can turn off. I can also imagine protections such as access only being allowed after no activity for a period of time e.g. 3 months.

Again this is a Proof of Concept and in that context, it is great to push Ethereum forward and create discussion.

Looking at solutions that will work for the future users, including my parents. 😄

---

<div class="post-metadata">

**Author:** ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)\
**Post date:** [October 27, 2019, 11:37pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/5 "2019-10-27T23:37:16Z")

</div>

Hi @pr0toshi,

Welcome to the community 👋

> [@spalladino](#):
>
> this process consumes a lot of gas; but recovery should not be a frequent operation.

You can try it yourself 😄  
Which is what I did, check out the gas usage below:

## Create new identity

Contract creation transaction:  
[https://rinkeby.etherscan.io/tx/0xfb5ad15e0b1363943598142e200c8ecca39e7660354d0e373283fc490878bfc3](https://rinkeby.etherscan.io/tx/0xfb5ad15e0b1363943598142e200c8ecca39e7660354d0e373283fc490878bfc3)  
Gas Used by Transaction: 5,140,801

## Recover identity

Recovery transaction:  
[https://rinkeby.etherscan.io/tx/0x13ce94befd5bf4fdac8110a1a6fd6deb8793e6327d79f976e64ef024b6323a43](https://rinkeby.etherscan.io/tx/0x13ce94befd5bf4fdac8110a1a6fd6deb8793e6327d79f976e64ef024b6323a43)  
Gas Used by Transaction: 4,648,095

---

<div class="post-metadata">

**Author:** ![wyc](https://avatars.discourse-cdn.com/v4/letter/w/f475e1/32.png) [@wyc](https://forum.openzeppelin.com/u/wyc)\
**Post date:** [October 28, 2019, 6:56am UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/6 "2019-10-28T06:56:35Z")

</div>

Just wanted to segue this into emerging W3C standards of verifiable credentials and decentralized identifiers, we were thinking something similar for any OAuth2 IDP. We have an opportunity to consolidate approaches of bridging Web2 into Web3 and leveraging massive existing network effects. Here’s our proposed DID method with similar risks that you highlight:

> **[did-oauth2 · master · Alpine / freeclaims.org](https://gitlab.com/alpinefresh/freeclaims.org/tree/master/did-oauth2)**
>
> GitLab.com

Disclosure of risks is probably the most important thing that makes this into an engineering option rather than an ideological debate.

---

<div class="post-metadata">

**Author:** ![spalladino](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/spalladino/32/22_2.png) [@spalladino](https://forum.openzeppelin.com/u/spalladino)\
**Post date:** [October 28, 2019, 2:34pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/7 "2019-10-28T14:34:39Z")

</div>

> [@abcoathup](#):
>
> You can try it yourself 😄  
> Which is what I did, check out the gas usage below:

Thanks @abcoathup for the experiment! FWIW, the code is far from optimized. The gas cost for recovering the identity can probably be considerably reduced.

As for the cost of deploying a new identity, by using minimal proxies it can be driven down by several orders of magnitude.

---

<div class="post-metadata">

**Author:** ![ivanvpan](https://avatars.discourse-cdn.com/v4/letter/i/97f17d/32.png) [@ivanvpan](https://forum.openzeppelin.com/u/ivanvpan)\
**Post date:** [October 28, 2019, 5:54pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/8 "2019-10-28T17:54:18Z")

</div>

Well, if things go down the path that, say, Argent has taken then a contract would have N recovery addresses a subset of which is required to unlock the contract. If some unpopular OAuth provider ends up being just one of a number of co-signers then there’s no loss to “decentralization” as far as I see. Of course the user would need to know not to trust only one entity. In case of, again, Argent that’s a real problem right now because Argent themselves are initially the only co-signer, so a lazy user would be trusting a young and unprofitable company. I suppose a protocol could demand that the user diversify their co-signers just like websites demand 2FA.  
EDIT: Actually, thinking about it, having a single recovery account is like having none at all, since if it is compromised then that’s all that’s needed to take over your main account.

---

<div class="post-metadata">

**Author:** ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)\
**Post date:** [October 28, 2019, 11:25pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/10 "2019-10-28T23:25:22Z")

</div>

# Social media

(including Twitter and Reddit)

## Tweet thread

[https://twitter.com/smpalladino/status/1188167083496005632?s=20](https://twitter.com/smpalladino/status/1188167083496005632?s=20)

[https://twitter.com/smpalladino/status/1188167085102456833?s=20](https://twitter.com/smpalladino/status/1188167085102456833?s=20)

[https://twitter.com/smpalladino/status/1188167093759434753?s=20](https://twitter.com/smpalladino/status/1188167093759434753?s=20)

[https://twitter.com/smpalladino/status/1188167096238333952?s=20](https://twitter.com/smpalladino/status/1188167096238333952?s=20)

[https://twitter.com/smpalladino/status/1188169811865559040?s=20](https://twitter.com/smpalladino/status/1188169811865559040?s=20)

## Tweets

(replies, apologies if I missed any)

[https://twitter.com/yulesa/status/1188521628348616706?s=20](https://twitter.com/yulesa/status/1188521628348616706?s=20)

[https://twitter.com/CharlieThomps0n/status/1188516954358865920?s=20](https://twitter.com/CharlieThomps0n/status/1188516954358865920?s=20)

[https://twitter.com/julien51/status/1188191595973267456?s=20](https://twitter.com/julien51/status/1188191595973267456?s=20)

[https://twitter.com/lumsdnb/status/1188912453662498816?s=20](https://twitter.com/lumsdnb/status/1188912453662498816?s=20)

[https://twitter.com/virgilgr/status/1188522376310378497?s=20](https://twitter.com/virgilgr/status/1188522376310378497?s=20)

## Reddit comments

(level 1 with more than 0 points, apologies if I missed any)

[moumous87](https://www.reddit.com/user/moumous87/) or [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnnwm2/we_built_a_poc_for_recovering_an_identity/f5dgmew/)

> Quickly read the comments and I had a WTF moment. I can understand that some people are following Ethereum only for speculations and don’t really know/understand much about software and blockchain development, and thus might not be familiar with concepts like Proof of Concept or Minimum Viable Product... But only in the US would people use an acronym to racially profile people.

[Onakander](https://www.reddit.com/user/Onakander/) on [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnm2hz/sign_in_with_google_to_your_identity_contract_poc/f5dlj8d/)

> This is antithetical to the entire point of decentralized tech. "Hey, let's make a centralized corporation able to "recover" (read: at any time usurp) your keys."

[vvpan](https://www.reddit.com/user/vvpan/) on [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnnwm2/we_built_a_poc_for_recovering_an_identity/f5foqv9/)

> The negative comments are very surprising and, frankly, enraging.
> 
> Firstly, they don't seem to know what a Proof of Concept is, it certainly is not a finished product, it just showcases a certain technical relationship as being possible. Not needed, not mandatory, but theoretically possible. This is how technological progress is achieved, btw.
> 
> Secondly, the UX of blockchain is terrible and only a tiny subset of technically able people use it and that is not likely to change if things are left as they are. I develop on top of Ethereum and even I don't want to take out my hardware wallet unless it is absolutely necessary (so like once a year). Too much is at stake and it's too easy to make a mistake and lose everything. Account recovery is one of the most under-researched topics so don't shit on people who are trying to improve the situation through experimentation.
> 
> Thirdly, if you knew something about account recovery you'd know that there are clever schemes (used by Argent for example) that allow you to recover by using a set of co-signers: a friend, a hardware wallet, the company that made the wallet. The scheme of signing via a an existing auth provider potentially gives you one more option - a real world account you already have, making on-boarding easier without sacrificing decentralization and making things more secure in the process.

[idiotsecant](https://www.reddit.com/user/idiotsecant/) on [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnnwm2/we_built_a_poc_for_recovering_an_identity/f5dssjj/)

> This is an interesting gadget, as long as google's JWT website sign on functionality is maintained and continues to work how it's supposed to.

[265](https://www.reddit.com/user/265/) on [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnnwm2/we_built_a_poc_for_recovering_an_identity/f5e9v85/)

> > given that most users already trust Google with their digital life
> 
> Haha, no thanks.

[ethstaking](https://www.reddit.com/user/ethstaking/) on [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnnwm2/we_built_a_poc_for_recovering_an_identity/f5e1udb/)

> Nice POC. Really shows the potential of ethereum but I would not trust google to recover my funds. Better to memorize the seed and the only one you have to trust is YOU

[ice0nine](https://www.reddit.com/user/ice0nine/) on [r/ethereum](https://www.reddit.com/r/ethereum/comments/dnnwm2/we_built_a_poc_for_recovering_an_identity/f5k5el7/)

> Very nice! What would even enhance your already good documentation would be a sample for a plain, (base64-)decrypted JWT (as done very nicely on [jwt.io](http://jwt.io)). This would ease the understanding, as I just dealt with JWT it's ok for me, but for someone new to this it might be overwhelming.

---

<div class="post-metadata">

**Author:** ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)\
**Post date:** [October 28, 2019, 11:34pm UTC](https://forum.openzeppelin.com/t/sign-in-with-google-to-your-identity-contract-for-fun-and-profit/1631/11 "2019-10-28T23:34:44Z")

</div>

Welcome to the community @wyc and @ivanvpan 👋

> [@wyc](#):
>
> Here’s our proposed DID method

Thanks for sharing.

> [@ivanvpan](#):
>
> Actually, thinking about it, having a single recovery account is like having none at all, since if it is compromised then that’s all that’s needed to take over your main account.

For me, I would want the recovery option to have some form of time delay protection. e.g. 3 months of in activity, or have a two stage process, where the recovery process is initiated (and any existing key can cancel), then completed after a time delay.
