Google One Tap login with Auth0
Tags: googleonetap, auth0, identity, auth
Published: 2023-05-21 14:02:02


Assuming that you've created the project in the [google developer console](https://console.developers.google.com/project) and configured the ClientID and ClientSecret in Auth0 under social connections. Let's see how you can enable login with Google One Tap using Auth0 and get the `id_token`

----

1. Letting the user log in using Google One Tap
1. Extract user email from the `id_token` by google
1. Use the extracted email to sign in with Auth0

----

### 1. Letting the user log in using Google One Tap

#### Include the google script (login.html)
```html
<script src="https://accounts.google.com/gsi/client"></script>
```


#### Include the HTML tag to trigger one tap flow on page load

```html
<div id="g_id_onload"
    data-client_id="GOOGLE_CLIENT_ID"
    data-context="signin"
    data-ux_mode="popup"
    data-callback="handleLogin"
    data-nonce=""
    data-close_on_tap_outside="false"
    data-itp_support="true">
</div>
```

Google will use this tag as the configuration and triggers the one tap flow on load.

> :construction:  Google uses something called [Exponential cool down](https://developers.google.com/identity/gsi/web/guides/features#exponential_cool-down), basically when ever you close the One Tap popup, it'll not show it again till the cool off period.
In order to see the popup, run this in the browser console and refresh the page ```document.cookie = `g_state=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT`;```

----

### 2. Extract user email from the ID_TOKEN by google

There is a `data-callback="handleLogin"` attribute in the above, which will be called once the user logs in using the One Tap flow.

The parameter for the `handleLogin` will contain the token from Google.

The `response` will look like this

```json
{
    "clientId": "YOUR_GOOGLE_CLIENT_ID",
    "client_id": "YOUR_GOOGLE_CLIENT_ID",
    "credential": "ID_TOKEN_WHICH_WILL_BE_A_JWT",
    "select_by": "user"
}
```

Google will give us the `id_token` from which we need to extract the user email. Since it's in JWT format we can use some [jwt decoding library](https://www.npmjs.com/package/jwt-decode) to parse it.

```javascript
function handleLogin(response) {
    const email = (jwt_decode(response.credential)).email;
}
```

Decoded JWT should look something like this

```json
{
  "iss": "https://accounts.google.com",
  "nbf": 1684674651,
  "aud": "YOUR_GOOGLE_CLIENT_ID",
  "sub": "105427290204744290733",
  "email": "USER_EMAIL",
  "email_verified": true,
  "azp": "YOUR_GOOGLE_CLIENT_ID",
  "name": "Shinchan Nohara",
  "picture": "https://lh3.googleusercontent.com/a/AGNmyxbMyc6kaGFYoe65-1eASeS6HwrIQt9HKD-qSyyp=s96-c",
  "given_name": "Shinchan",
  "family_name": "Nohara",
  "iat": 1684674951,
  "exp": 1684678551,
  "jti": "150ff9433d3511d76f10a443f8ab7beb94751477"
}
```

----

### 3. Use the extracted email to sign in with Auth0

Now that we have the users email we can trigger the `authorize` call from Auth0. The problem is, if we trigger the `authorize` call normally it'll refresh the page which defeats the purpose of OneTap login. In order to avoid that we need to authorize with Auth0 using an `iframe`

For that we need to host the `iframe.html` at some path on your domain and inside the `iframe.html` we can call the `authorize` with the connection type as `google-oauth2` and responseMode as `web_message`.

`iframe.html`
```html
<html>

<head>
    <script src="https://cdn.auth0.com/js/auth0/9.18/auth0.min.js"></script>

    <script>
        const webAuth = new auth0.WebAuth({
            domain: 'YOUR_DOMAIN.auth0.com',
            clientID: 'AUTH0_CLIENT_ID'
        });

        // we need this message to receive the extracted
        // google email from the parent window
        window.addEventListener('message', (event) => {
            // verify if the `message.origin` matches to the 
            // original origin for security purposes
            webAuth.authorize({
                connection: 'google-oauth2',
                login_hint: event.data, // this is the email
                responseType: 'id_token',
                redirectUri: 'YOUR_DOMAIN.auth0.com/callback',
                responseMode: 'web_message',
                //Any additional options can go here
                params: { 'myAdditionalParam': 'something' }
            }, function (err, authResult) {
                console.log(err)
            });
        });
    </script>
</head>
</html>
```

We need to load the `iframe` in `login.html` and pass the extracted user email from the Google response to Authorize. Once the authorization is completed the `iframe` will `postMessage` the token to the parent(`login.html`). We can add a message event listener to receive the token from the iframe.

`login.html`

```js
function handleLogin(token) {
    const user_email = (jwt_decode(token.credential)).email;
    const iframe = document.getElementById("auth_iframe")
    iframe.src = "/iframe.html"
    iframe.onload = () => {
        iframe.contentWindow.postMessage(user_email);
    }
}

window.addEventListener("message", (event) => {
    // verify if the `message.origin` matches to the original 
    // origin for security purposes
    console.log(`Token: ${event.data.response.id_token}`)
    // Here you have the Auth0 id_token
}, false);
```


:rocket: Now you have the `id_token`