Dana
Dana

Reputation: 713

Actions on Google account linking

Following documentation described here, I have account linking set up with implicit grants and find that it works well when testing with the browser / actions console, and also with the Google Home app for Android. Unfortunately on the iphone version of the app, user auth hangs most of the time. Feedback from actions on google support is that the problem is that google sign in flow is implemented in separate browser tab (window). On iphone you can't open 2 windows in SfariViewController, thus they are re-writing address of the first page and can’t finish sign in flow. This is known issue and they are not planning to change this. The solution is to implement sign in flow all in one browser window. I'm unclear how to do this and am looking for someone to share code behind the authorization URL you set up that works consistently on iphone. Below is the core of what I am using:

.html snippet:

<!DOCTYPE html>
<html>
<head>
  <title>Authorization Page</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="google-signin-client_id" content="948762963734-2kbegoe3i9ieqc6vjmabh0rqqkmxxxxx.apps.googleusercontent.com">
  <!-- <meta name="google-signin-ux_mode" content="redirect"> INCLUDING THIS META TAG BREAKS THE AUTH FLOW -->
  <script src="js/googleAuth.js"></script>
  <script src="https://apis.google.com/js/platform.js" async defer></script>
  <link rel="stylesheet" href="css/googleAuth.css">   
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">  
</head>
<body>
<header class="bgimg-1 w3-display-container w3-grayscale-min" id="loginScreen">
  <div class="w3-display-topleft w3-padding-xxlarge w3-text-yellow" style="top:5px"> 
    <span class="w3-text-white">Google Sign In</span><br>
    <span class="w3-large">Sign in with your Google account</span><br><br>
    <div class="g-signin2" data-onsuccess="onSignIn"></div><br><br>        
  </div>   
</header>
</body>
</html>

.js code snippet:

function onSignIn(googleUser) {
  var profile = googleUser.getBasicProfile();
  var id = profile.getId()
  var name = profile.getName()
  var email = profile.getEmail()
  var token = googleUser.getAuthResponse().id_token;
  var client_id = getQueryVariable('client_id')
  // vital-code-16xxx1 is the project ID of the google app
  var redirect_uri = 'https://oauth-redirect.googleusercontent.com/r/vital-code-16xxx1'
  var state = getQueryVariable('state')
  var response_type = getQueryVariable('response_type')

  // store the user's name, ID and access token and then sign out
  storeOwnerID (email, name, id, token, function() {
    // sign out
    var auth2 = gapi.auth2.getAuthInstance();
    auth2.signOut().then(function () {
      console.log('signed out')
    });
    // if this page was loaded by Actions On Google, redirect to complete authorization flow
    typeof redirect_uri != 'undefined' ? window.location = redirectURL : void 0    
  }) 
}

function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split('&');
  for (var i = 0; i < vars.length; i++) {
    var pair = vars[i].split('=');
    if (decodeURIComponent(pair[0]) == variable) {
      return decodeURIComponent(pair[1]);
    }
  }
  console.log('Query variable %s not found', variable);
}

Upvotes: 2

Views: 1014

Answers (2)

Dana
Dana

Reputation: 713

With help from Google support & engineering, this is now resolved:

  1. As noted above, I had to include this meta tag: <meta name="google-signin-ux_mode" content="redirect">
  2. I needed to have https://my-auth-endpoint.com/ in my project's authorized redirect URI. It is not enough to have it only in Authorized javascript origins. The other key thing is to include the trailing slash, I hadn't originally and it will not work without it.

Below is the simple code foundation you can use to get a working version of an authorization endpoint for actions on google account linking:

.html:

<!DOCTYPE html>
<html>
<head>
  <title>Authorization Page</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="google-signin-client_id" content="948762963734-2kbegoe3i9ieqc6vjmabh0rqqkmxxxxx.apps.googleusercontent.com">
  <meta name="google-signin-ux_mode" content="redirect">
  <script src="js/googleAuth.js"></script>
  <script src="https://apis.google.com/js/platform.js" async defer></script>
  <link rel="stylesheet" href="css/googleAuth.css">   
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">  
  <script>
    sessionStorage['jsonData'] == null ? storeQueryVariables() : void 0
  </script>
</head>
<body>
<header class="bgimg-1 w3-display-container w3-grayscale-min" id="loginScreen">
  <div class="w3-display-topleft w3-padding-xxlarge w3-text-yellow" style="top:5px"> 
    <span class="w3-text-white">Google Sign In</span><br>
    <span class="w3-large">Sign in with your Google account</span><br><br>
    <div class="g-signin2" data-onsuccess="onSignIn"></div><br><br>        
  </div>   
</header>
</body>
</html>

.js:

// Retrieve user data, store to DynamoDB and complete the redirect process to finish account linking
function onSignIn(googleUser) {
  let profile = googleUser.getBasicProfile(),
      id = profile.getId(),
      name = profile.getName(),
      email = profile.getEmail(),
      token = googleUser.getAuthResponse().id_token,
      redirect_uri = 'https://oauth-redirect.googleusercontent.com/r/vital-code-16xxxx',
      jsonData = JSON.parse(sessionStorage['jsonData']),
      redirectURL = redirect_uri + '#access_token=' + token + '&token_type=bearer&state=' + jsonData.state

  // store the user's name, ID and access token
  storeUserData(email, name, id, token, function() {
    // sign out of google for this app
    let auth2 = gapi.auth2.getAuthInstance();
    auth2.signOut()
    // if this page was loaded by Actions On Google, redirect to complete authorization flow
    typeof redirect_uri != 'undefined' ? window.location = redirectURL : void 0    
  })   
}

// Store the user data to db
function storeUserData (email, name, id, token, callback) {
  // removed for simplicity
}

// Store URI query variable 'state' to browser cache
function storeQueryVariables() {
  let qvar = {
    'state': getQueryVariable('state')
  }
  storeLocally(qvar)
}

// Get any variable from incoming URI
function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split('&');
  for (var i = 0; i < vars.length; i++) {
      var pair = vars[i].split('=');
      if (decodeURIComponent(pair[0]) == variable) {
          return decodeURIComponent(pair[1]);
      }
  }
  console.log('Query variable %s not found', variable);
}

// Store JSON object input to local browser cache 
function storeLocally (jsonData) {
  if (typeof(Storage) !== 'undefined') {
    sessionStorage['jsonData'] = JSON.stringify(jsonData)
  } else {
    console.log('Problem: local web storage not available')
  }
}

Upvotes: 1

Yury Ramanchuk
Yury Ramanchuk

Reputation: 76

@dana Have you tried adding meta tag?

<meta name="google-signin-ux_mode" content="redirect">

Upvotes: 1

Related Questions