site-kit-wp: Deep links don't support secondary Google accounts

Bug Description

Google allows for multiple accounts to be signed-in simultaneously.

When a user is logged-in to multiple accounts at once, links to Google services assume your “default user” if it is not otherwise defined in the url, usually as an authuser=x query parameter (where x is an integer starting at 0).

This causes our deep links (i.e. linking to a specific Analytics view or search console report) to fail if the Google user authenticated with Site Kit is not the user’s default user.

The index to use for authuser is unknown to us, and does not appear to be exposed via any API. However, some services are known to support using the user’s email address for this parameter instead.

Steps to reproduce

  1. Sign out of all Google Accounts
  2. Sign in to account A without access to a Search Console property ( this is considered the primary account )
  3. Sign in to account B with access to a Search Console property
  4. Set up Site Kit using account B
  5. Go to the Site Kit dashboard
  6. Click on the first link under “Top search queries for your site”
  7. See error that your user does not have access to this property

Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance criteria

  • Direct “deep” links to Google resources should always include the authuser query parameter which is set to the user’s email address from their profile (user option googlesitekit_profile). All Google APIs we use primarily rely on the authuser parameter except:
    • AdSense, which however support a similar mechanism by including a URL segment like /u/0 (for example https://www.google.com/adsense/new/u/0/pub-1234567890/home) - this can also be /u/user@gmail.com, in which case it will automatically handle the correct user.
    • PageSpeed Insights does not have any user association, so can be ignored entirely here.
  • There should be a new selector getServiceURL( args = {} ), where args supports optional fields path (should be sanitized to start with forward slash) and query (should be a map that will be sanitized into a query string), on the following datastores (email in the references below would be the user’s email from core/user store):
    • modules/analytics: Should return https://analytics.google.com/analytics/web/?authuser={email}#{path}{query}
    • modules/tagmanager: Should return https://tagmanager.google.com/?authuser={email}#{path}{query}
    • modules/optimize: Should return https://optimize.google.com/optimize/home/?authuser={email}#{path}{query}
    • modules/search-console: Should return https://search.google.com/search-console{path}{query} - query includes authuser={$email}
    • modules/adsense: Should return https://www.google.com/adsense/new/u/{email}{path}/{query}
    • modules/pagespeed-insights: Should return https://developers.google.com/speed/pagespeed/insights{path}{query}
    • If path or query are empty, they shouldn’t be sanitized, i.e. the returned URL shouldn’t include any single ? segment or so.

Implementation Brief

  • Create a new selector for each of the 6 modules called getServiceURL following the AC for implementation details in regards to the parameters and validation of them.
    • The selector should be able to access the core/user datastore to retrieve the userEmail
      • Refer to the AC’s for how each of the 6 URLs is formatted.
  • assets/js/modules/search-console/dashboard/dashboard-widget-keyword-table.js
    • Convert class component to functional component but continue to pass component to withData HOC as there is not a datastore equivalent.
    • Generate the links using the getServiceURL selector passing the appropriate path and query items as the args parameter
  • assets/js/modules/search-console/dashboard/dashboard-widget-popular-keyword-table.js
    • Convert class component to functional component but continue to pass component to withData HOC as there is not a datastore equivalent.
    • Generate the links using the getServiceURL selector passing the appropriate path and query items as the args parameter
  • assets/js/modules/analytics/dashboard/dashboard-widget-top-pages-table.js
    • Convert class component to functional component but continue to pass component to withData HOC as there is not a datastore equivalent. *Generate the links using the getServiceURL selector passing the appropriate path and query items as the args parameter
    • Complete and merge #1789

QA Brief

Steps to reproduce issue:

  1. Sign out of all Google Accounts
  2. Sign in to account A without access to a Search Console property ( this is considered the primary account )
  3. Sign in to account B with access to a Search Console property
  4. Set up Site Kit using account B
  5. Go to the Site Kit dashboard
  6. Click on the first link under “Top search queries for your site”
  7. See error that your user does not have access to this property
  8. In the Analytics tab, click on any links in Top Content.
  9. See error that your user does not have access to this property

After building this branch, none be sure to log out of all accounts and log in again. These errors should not occur.

Since the PR touches several areas, we should also thoroughly test a few other areas especially. For those, the focus should be on ensuring there’s no breakage - there are no specific AC criteria that these need to fulfill:

  • The AdSense setup flow (all different states, via QA Tester plugin).
  • The Analytics provisioning flow (create new account).
  • On the Site Kit dashboard and module pages: All “source” links and links on e.g. URL or page lists that point to a Google service frontend should be valid. We don’t need to look in detail at the exact URLs here, but we should make sure there are no broken URLs.

Changelog entry

  • Consistently enhance deep links to Google services to support users logged into multiple Google accounts in their browser.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 20 (13 by maintainers)

Most upvoted comments

@ryanwelcher you still have a few references to getServiceBasedURL 😄

let’s use getServiceURL instead of getServiceBaseURL for all selectors here.

I’ve updated the AC and IB to reflect the change.

@felixarntz sounds great. I’ll move forward with your suggestion, thanks!

@felixarntz as per slack, we’ve discovered that using the /u/{email} approach for search-console only works if the user is logged into more than one account. As discussed, I’ll update the AC’s to indicate that search-console should be passed the authuser query param which works in either case.

Adsense functions as expected so no change is required.