Google One Tap login with Auth0
Murali Krishna
Posted on May 21, 2023
Assuming that you've created the project in the google developer console 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
- Letting the user log in using Google One Tap
- Extract user email from the
id_token
by google - 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)
<script src="https://accounts.google.com/gsi/client"></script>
Include the HTML tag to trigger one tap flow on page load
<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.
🚧 Google uses something called 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
{
"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 to parse it.
function handleLogin(response) {
const email = (jwt_decode(response.credential)).email;
}
Decoded JWT should look something like this
{
"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>
<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
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);
🚀 Now you have the id_token
Posted on May 21, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.