Google-api-javascript-client: Multiple sign-in

Created on 7 Jan 2015  ยท  80Comments  ยท  Source: google/google-api-javascript-client

_From gengkev on February 05, 2012 17:44:36_

What steps will reproduce the problem? 1. Initiate the OAuth2 flow What is the expected output? What do you see instead? I expect to be able to choose what user I would like to sign in with, like in the regular flow, but it redirects to use the first account I am signed into. Please provide any additional information below.

_Original issue: http://code.google.com/p/google-api-javascript-client/issues/detail?id=11_

21+ stars Priority-Medium auth bug imported

Most helpful comment

If you add the parameter prompt: 'select_account' the user will be prompted to select their account (or add a new account), which I think should help with case where a user is signed in to a single account, but wanted to use a different one. Can you give that a try?

E.g. gapi.auth2.signIn({ prompt: 'select_account' });

All 80 comments

_From phenome on March 27, 2012 11:38:44_

@gengkev
Same here. I use three google accounts. It 'bypasses' regular flow and selects the default account, without enabling me to choose.


You can ask for a specific gapps domain by passing an "hd" parameter to OAuth with the name of the gapps domain you want to authorize against. On my app I actually prefer this method as it's more streamlined for my users.

Got from: https://developers.google.com/accounts/docs/OAuth (Should this be on OAuth 2.0 docs, since it works? I couldn't find it there.

Example:
api.auth.authorize({client_id: clientid, scope: scopes, immediate: false, hd : "yourdomain.com"},callback);

_From gengkev on May 03, 2012 13:45:58_

I keep forgetting to reply, and more recently I couldn't log into Google Code (?) but that really helped a lot, thanks!

_From gengkev on May 03, 2012 13:46:19_

I'm guessing it's some legacy parameter that works just because.

_From [email protected] on May 07, 2012 11:24:03_

Multi-login is not supported by the JS Client. It chooses the primary or user 0 by default. We have logged a request for multi-login support.

Status: Accepted
Owner: [email protected]
Cc: [email protected]

_From [email protected] on October 11, 2012 09:56:28_

Yo can add the parameter authuser with nothing value.

gapi.auth.authorize({client_id: googleDrive.CLIENT_ID,
scope: googleDrive.SCOPES,
immediate: (isImmediate) ? true : false,
authuser:""

_From gengkev on November 03, 2012 17:27:25_

Switching kind of works for me now: you can select the user in the top-right in the authorization prompt.

_From [email protected] on November 09, 2012 18:05:05_

Switching is not working for me.

In the Account Chooser popup, when I pick a different account a new TAB is open in the original window (leaving the popup open). When I provide authorization by clicking "Allow" in the new TAB the TAB title says "Connecting" and it never goes back to the original TAB that triggered the popup in the first place.

Is this expected behaviour? Should I open a new issue for this situation?
Thanks

_From gengkev on November 09, 2012 18:07:29_

Oops, didn't even test that. Silly me, you're right, it doesn't work.

_From [email protected] on November 09, 2012 22:56:10_

How can this be priority medium?
Developers have no control over how many Google accounts their customers use. Therefore the library is effectively unusable for the majority of situations. afaik, this show-stopping restriction is not even documented anywhere.

_From [email protected] on November 14, 2012 09:13:23_

We had a discussion on this at SO: http://stackoverflow.com/questions/13366254/how-do-i-get-a-prompt-for-which-google-account-to-use-when-using-the-js-client-l we tried everything suggested, we can't get it to work for anything but the current default user.

_From [email protected] on November 14, 2012 12:33:22_

Not that I am proud of my workaround of anything, but this is how we sorted it out:
-Whenever we get an access token for the wrong account, we detect it by asking for the state of the response. If we get a 403 (forbidden) we retry the authorization sending an incremented 'authuser' value.

That is,
gapi.auth.authorize({client_id: googleDrive.CLIENT_ID,
scope: googleDrive.SCOPES,
immediate: true,
authuser:accountIndex});
if(responseStatus == 403){
gapi.auth.authorize({client_id: googleDrive.CLIENT_ID,
scope: googleDrive.SCOPES,
immediate: true,
authuser:accountIndex++});
}

I hope this helps some of you users and helps you coders realize what sorts of kludges we developers are forced to code.

Cheers!

_From [email protected] on November 14, 2012 16:17:24_

11 is creative, but I think it relies on the user to log into the correct account on another tab to indicate the correct one. This is a different experience to our every other multiple account supporting application does it, I'd say.

But rather than pollute the thread I'll continue the conversion OOT - https://plus.google.com/u/0/106160348960403302854/posts/j9v9T2kfpAH .

_From [email protected] on April 17, 2014 22:16:06_

hjkjhkhkh

_From [email protected] on April 18, 2014 09:54:03_

Reassigning this. Is it still relevant?

Owner: [email protected]
Cc: [email protected]

_From [email protected] on April 18, 2014 10:04:50_

Yes

_From [email protected] on April 18, 2014 13:00:04_

Multi-login prompting is now supported when initiating the OAuth2 flow through the gapi.signin (ie. widget or gapi.auth.signIn()) library. Switching accounts should only be a matter of gapi.auth.signOut() followed by gapi.auth.signIn() again.

The user selector is a popup so it's still necessary for a user action to trigger the gapi.auth.signIn() call to avoid popup blocker issues.

gapi.auth.authorize() is ultimately where this behavior is implemented, so also should work, though it's not the preferred method.

davidjgraph, can you expand upon what you might be seeing that's missing?

_From [email protected] on June 24, 2014 00:24:52_

Hello,

if user has multiple google accounts, after initiating gapi.auth.signIn callback is called immediately with status.signed_in === true and in the same time popup is shown where user should choose preferred account to sign in with.

What is the recommended way to defined if user already chose an account? Is authuser == 1 in callback is reliable?

_From [email protected] on June 24, 2014 01:41:50_

It seems to be working using authorize(), thanks.

_From [email protected] on August 07, 2014 08:53:08_

To clarify here, I'm still having the problem with not being able to choose an account if there are multiple signed-in.

@Pavel - I'm using the preferred window.gapi.auth.signIn() method, but are you saying that before calling this, we should also be calling window.gapi.auth.signOut()?

_From [email protected] on August 07, 2014 09:01:39_

Whenever I use the signOut method before the signIn method, the current flow happens; I'm shown the multiple-accounts popup but can see back in the main window that my default account has already been signed in and the callback triggered.

_From [email protected] on November 26, 2014 04:36:11_

I have the same problem still. To reproduce:

  • Open Google Chrome in Incognito mode
  • Do gapi.auth.signIn()
  • When user wants to logout, do gapi.auth.signOut()
  • Then when user try to login again with gapi.auth.signIn(), it is immediately authorised without popup

+1 on this issue

For now I found that setting authuser: -1 achieves the behavior I'm looking for, which is always cause the auth dialog to display. But I'm a little nervous that this is a not-really-documented feature -- I worry that it will change in the future. It would be great to have an officially sanctioned solution.

+1

Any official solution would be great.

+1

+1

I have a half decent workaround that doesn't involve any hacks. Basically communicate to your users that they need to add a new account to sign into your service. So beside your "sign in with google" button have a "add a google account" button open a new tab at https://accounts.google.com/login

Once they use that screen to add a new account, gapi.auth2.signIn on your site and the like should prompt a popup with multi-user select.

I can confirm as of writing that this issue really only presents in the case where there is only one google account signed into, meaning users cannot "sign out and switch accounts" for you're service when they click your "sign into google" button (you get that open and instantly close popup).

What google needs to do is remove some automation that exists somewhere in their api. Basically from what I guess is that on auth2.signIn, it checks to see how many accounts are present, if there is only one, and the permissions for your app/service have already been granted, then make that user "sign in", when really, they should still prompt with that account select screen, so users have the option to add a new account (much like they do when 2 accounts are present they can add a 3rd, 4th... etc), it's really just an edgecase at this point

UPDATE:
There is another workaround, where on app startup, call auth2.disconnect(), which will revoke the permissions accross the board. so when they hit sign in, you are guaranteed the add account screen. The caveat being that they need to "grant permissions" each time, which is ugly in a different way, pick your poison basically.

I am really starting to wonder if it is worth continuing on this library. No open source so we can't look at the issues ourselves, 120 open issues, seemingly no support at all no updates on the announcements blog for 4 years....
Basically the implementation is broken and gives us very little control. No option to not use a popup for example. The reason I was using this was for token refreshes but it doesn't even do that automatically.

I have simple requirements, let a user log into their google account and then then they return automatically log them back into the same account that they logged into last time. It seems that this is impossible.

I have 3 google accounts. If I set the authuser param when calling gapi.auth.authorize I can specify which user is logged in (when using immediate, on first time login pass -1 so the user selects their account).
This is so close to working but not quite - when the user initially logs in we are not informed which account (i.e. 0,1 or 2) so that when they return we can't pass the correct value in to log them in again to the same account.

I think that I will just have to force them to login each time, if I'm doing that I may as well dump the whole library as I don't care about refreshing the token then.

If you add the parameter prompt: 'select_account' the user will be prompted to select their account (or add a new account), which I think should help with case where a user is signed in to a single account, but wanted to use a different one. Can you give that a try?

E.g. gapi.auth2.signIn({ prompt: 'select_account' });

I do not have an issue getting a user to select a different account. I have an issue with logging the user back into that same account when they return to the site and the token has expired.

โณ 4 years have passed since the bug was first created. We'll be moving onto the 5th year hitting February in two months. Are there really no plans to fix this?

I've given up on the supplied authentication client and wrote my own client / server for this:
https://github.com/Roaders/GoogleOAuthServer/blob/master/README.md

bump

Hi @Roaders, I apologize that this issue has been opened for so long. I will try to help. It seems that you are using gapi.auth. This library has been deprecated and we recommend migrating to gapi.auth2. This new library handles properly logging the user back in on initialization, and also handles token refresh. Head over here for more information.

@flawiddsouza is your issue the same than @Roaders ? Or is it the automatic selection of account that is the issue? As @WilliamDenniss mentions, signIn({prompt: 'select_account'}) should allow the user to change.

@czzarr which one is the issue you encounter?

@TMSCH I'm using auth2. I already get the option to select accounts but selecting anything other than the main account has no effect. It just refuses to login.

You can check for yourself here: https://flawiddsouza.github.io/youtube-playlist-viewer/

@flawiddsouza I was able to successfully sign in with multiple accounts on your app. There was some issues with the actual youtube feature but the authentication seemed to work fine. What exactly happens for you? Could you give me a step by step process to try to reproduce the issue?

Hi @TMSCH
Would it be possible to have a snippet that shows how to do token refresh and handle multiple accounts so that the user can select the correct one only after having transparently tried the currently signed in one? (the web sign-in documentation isn't clear to me, and there is little consistency between samples which further adds to the confusion)

@TMSCH Did you check your chrome console (assuming you're using chrome)? First account always authenticates fine, selecting the second or third account returns this error:
Object {type: "tokenFailed", idpId: "google", error: "USER_LOGGED_OUT"}
It's logged by the console.

@flawiddsouza I do get an error upon signing in another user but this is related to a call to the Youtube API, I don't get the error you get. Here is what I do:

@czzarr token refresh is handled by the gapi.auth2 library itself. If you don't need to have a refresh_token in the backend, you don't have to do anything special to always have a valid access_token in the client.
Upon initializing, gapi.auth2 will automatically sign in the user if there was a previously signed in user to the app, and load a fresh access_token. Does that answer your concern?

@TMSCH This is bizarre, I followed the same steps. I still get the same error. It never signs to the second or third account but it always accepts the first one. There's are a few stackoverflow threads on this: https://stackoverflow.com/questions/34507769/google-login-fail-with-youtube-accounts
https://stackoverflow.com/questions/37951665/google-sign-in-gives-error-when-swiching-to-secondary-youtube-accounts
https://stackoverflow.com/questions/35393991/google-webcomponents-youtube-sign-in-fails
The thing I notice in common, is that it's a youtube channel that I'm trying to sign-in to. Maybe that's the reason the sign in fails?

@flawiddsouza what do you mean by sign-in to a YouTube channel? This is maybe why I can't reproduce this. I used two Google accounts for which I had created YouTube channel. Is that the same thing than you did?

YouTube gives you an option to create multiple channels. These individual channels are given their own google accounts. See: https://www.youtube.com/channel_switcher. The account selector thus treats them as individual accounts, even if you're logged into a single account. Going to https://accounts.google.com/ shows that I have three accounts. 2 belonging to the youtube channels. I can login to these accounts individually or access them directly through the main account.

@flawiddsouza thanks for the further information. I was able to reproduce the issue now. We are going to investigate, I'll keep this thread updated.

I have read the entire thread, I'm also facing a similar issue, mostly similar with @Roaders '
My issue is this. I'm using google picker and I'm doing the authorization something like this: gapi.auth2.authorize( { 'client_id': clientId, 'scope': scope, 'immediate': false }, handleAuthResult );

Everything works fine, excepting this thing: When I have multiple users logged in the browser, it logs in successfully with one of them, but every time the user returns and chooses the same account I get an this internal error TypeError: (b || "").split is not a function. If I'm choosing another account and after that I choose the initial account it works.

If I'm using auth instead of auth2 (google's older deprecated API) with the parameter 'authuser: -1' it works fine. Has anyone faced this, is there a workaround? Am I doing something wrong?

Hi @alexghi, you are actually using an unreleased method ;). Its behavior may change in the future, so I wouldn't recommend relying on it for now. I'll update this thread when it is available.

For your use case, you'd rather want to use gapi.auth2.init/signIn. It will take care of automatically signing in the user the next time they reload your application, even when several Google accounts are logged in.

Head to the doc for more information on how to use integrate it.

Regarding the issue you get, I'd be interested to know more as I am not able to reproduce it. What browser/platform are you using? Could you provide a minimal code snippet that reproduces the issue (i.e. what does the handleAuthResult method does)? Could you also provide the full console trace?

Thanks!

Hey, thanks for the quick response @TMSCH; I don't understand how is it unreleased since I followed the reference closely. Here's the example I have followed doc . It happens in any browser I have tested so far (Chrome, FF, Safari), and I'm using MacOS (10.12.2). You can take a look at this gist (you'll have to update it with your configs).

Please let me know if there's a solution. Thanks

@alexghi the doc you pointed to is for Google Sign-In v1, and uses gapi.auth.authorize, when your snippet uses GSI v2, gapi.auth2.authorize ;). We're going to update it.

Your bug comes from the scope argument you are passing. GSI v2 does not accept a list of scope, it has to be a comma-delimited string (e.g. 'scope1 scope2'). Change to 'https://www.googleapis.com/auth/drive' instead of ['https://www.googleapis.com/auth/drive'] and it will work.

@TMSCH thanks a lot for the explanations. The documentation sometimes feels counterintuitive. Really appreciate your support. Thanks again.

@alexghi you're welcome! Feel free to create an issue every time you feel the documentation is not clear. We're happy to improve it!

@flawiddsouza we have released a fix to the issue with multiple login accounts. I was able to verify that I don't observe the issue anymore, let me know if you still experience problems!

Thanks, it's working perfectly now ๐Ÿ‘

But sometimes when switching accounts, I get this error while retrieving a playlist that was retrieved from that account: "The request is not properly authorized to retrieve the specified playlist". It's weird. It happens randomly and without a cause. It's only the 'likes' playlist that's giving me this problem. All other playlists can be retrieved without an error. Was there an API change?

Glad it's working!

About the issue you are observing now, could you look at the network tab, and find the request to retrieve the playlist? Could you copy paste the request and response?

Also, is there any console logs?

{
 "error": {
  "errors": [
   {
    "domain": "youtube.playlistItem",
    "reason": "playlistItemsNotAccessible",
    "message": "The request is not properly authorized to retrieve the specified playlist.",
    "locationType": "parameter",
    "location": "playlistId"
   }
  ],
  "code": 403,
  "message": "The request is not properly authorized to retrieve the specified playlist."
 }
}

The console log and network response are the same as the above.

The request:
https://content.googleapis.com/youtube/v3/playlistItems?maxResults=50&pageToken&part=snippet&playlistId=LLQqX1OQ5DM38JRabHrkX44A&fields=nextPageToken%2C%20items%2Fsnippet%2FresourceId%2FvideoId%2C%20items%2Fsnippet%2Fthumbnails%2Fmedium%2Furl%2C%20items%2Fsnippet%2Ftitle%2C%20items%2Fsnippet%2FpublishedAt

Also, this error seems to disappear after two page refreshes. As in after two subsequent logins, I think.

Hmm, the request doesn't seem to have any access_token in the query params. Could you check the request payload?

How do I check that? I'm not finding any access_token parameter in the query params. Here's all I found under query string parameters:
maxResults=50&pageToken&part=snippet&playlistId=LLhx4F6sprkaorZJbekT6aaQ&fields=nextPageToken%2C%20items%2Fsnippet%2FresourceId%2FvideoId%2C%20items%2Fsnippet%2Fthumbnails%2Fmedium%2Furl%2C%20items%2Fsnippet%2Ftitle%2C%20items%2Fsnippet%2FpublishedAt

@flawiddsouza right that makes sense, this is indeed all the params sent.

In the Network tab, could you click on the request that fails with a 403, and in the "Headers" tab of the request details, look for an "Authorization:Bearer xxxxxx" entry? Is there one? If there is, could you make sure that this is the same access_token than the one present in the AuthResponse of the user? (gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse(true);)

@alexghi, the new feature is now documented: https://developers.google.com/identity/sign-in/web/reference#advanced

@TMSCH thanks for pointing it out.

@TMSCH

I've tried reading through the above but I'm still confused as to what I need to do. I'm following this document: https://developers.google.com/identity/protocols/OAuth2UserAgent#identify-access-scopes

I'm signing in with a google account which has multiple youtube channels associated with it. Once I'm authorized for one of the channels... I do an api request for that channel to get its channel id like this:

      gapi.client.youtube.channels.list({
          part: 'contentDetails,snippet',
          id: null,
          mine: true

        })
        .then(function(data){
          console.log(data);
        });

This is successful and I get the channel id no problem. However... if I sign out/revoke access and then sign back in and select a different channel... it keeps returning the first authenticated channel despite the fact that I presumably signed out. I can't get it to authorize a different channel on that google account unless I do an "empty cache and hard reload" on my chrome browser and then sign in.

@fieyr thanks for raising this issue. I reproduced the issue myself. However, I am not able to get another channel ID than the one from my Google Account, main channel. Even clearing the cache. I wonder if that would mean the issue comes from the API, not the authentication.

Here is what I did:

  1. Sign in with Google Account UserA, asking for https://www.googleapis.com/auth/youtube scope, and select YouTube Channel "UserA" (the main one).
  2. Use your code snippet to load the account's main channel. Channel ID noted as ID1.
  3. Open a new incognito window.
  4. Sign in with Google Account UserA (same youtube scope), selecting YouTube channel "OtherChannel".
  5. Use your code to load the account's main channel. The channel ID is the same than ID1.

Is that the right reproduction steps? If yes, could you share how you authenticate the user? (i.e. a minimal snippet of code to reproduce the issue would be very helpful)

Thanks!

@TMSCH Very strange. I hadn't thought of trying an incognito window to test the second channel. However when I did, it returned the correct channel id ID2. Your steps above are essentially the right steps with the exception that I haven't been using an incognito window and instead simply revoked access after first signing into UserA > Main channel (ID1) and then tried to sign in again to the same UserA account but then into OtherChannel (ID2)... but received ID1 instead of the expected ID2. The fact that you weren't able to get a different channel ID after clearing your cache is definitely a surprise to me since it ONLY changes IDs for me if I do that. Not very user friendly for my users if they want to easily switch YouTube channels! :)

If you don't mind, I will simply post all of the code here since I have it all in one file for my test. (I created a test project to see if this was fixed). This code is directly copied from the google oauth2 document linked above... with the exception that I added my API request for the channel ID in the if (isAuthorized) { block. I log that response to the console. You'll obviously need to substitute in your own api key and client id.

Thank you for taking the time to look at this. I actually have built a very cool app for YouTube that solves a major problem for me and I think a lot of other YouTube users as well. I've literally been sitting on it for over a year without taking it public because of this issue. I didn't feel like it was ready for the public with these kinds of annoying login issues. If I could get this fixed, it would be an enormous help.

<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/youtube';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // Retrieve the discovery document for version 3 of Google Drive API.
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from API Console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'discoveryDocs': [discoveryUrl],
        'clientId': 'YOUR_CLIENT_ID',
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      }); 
      $('#revoke-access-button').click(function() {
        revokeAccess();
      }); 
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked 'Sign out' button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus(isSignedIn) {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');

      gapi.client.youtube.channels.list({
          part: 'contentDetails,snippet',
          id: null,
          mine: true

        })
        .then(function(data){
          console.log(data);
        });   

    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus(isSignedIn) {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js" 
        onload="this.onload=function(){};handleClientLoad()" 
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>

@TMSCH I've been thinking about this a bit more... and this is just a guess... but it's almost as if the google account selector (where you pick your channel) is caching the selection of the first channel so that even if I revoke my token/sign out.... the next time I log in and go to select another channel... it uses that cached value of the account I selected to authenticate instead of the otherchannel I selected.

I think I've got the same issue.

@TMSCH Here's info for the asked query.

Authorization:Bearer ya29.Gl03BNRxy-J2pkjRNjlXLbEid1ySYtAs8ogeSwo3yTBVJkri7DjSeLvrahkDnts8Xb-L1LaX_zPqx3fOwKTYQVf911zX3GR6gurWxH1Ywj-ArbVNlGBrY-xdCnAV9SM

gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse(true) access token:
"ya29.Gl03BNRxy-J2pkjRNjlXLbEid1ySYtAs8ogeSwo3yTBVJkri7DjSeLvrahkDnts8Xb-L1LaX_zPqx3fOwKTYQVf911zX3GR6gurWxH1Ywj-ArbVNlGBrY-xdCnAV9SM"

They both seem to be the same.

Thanks @fieyr and @flawiddsouza for the further information. I will investigate on my end in more details as I don't see any obvious issue, and keep you updated. Sorry about the inconvenience.

@TMSCH I'll post detailed screenshots later to show exactly what's happening.

Thanks @fieyr. Actually, instead of screenshot, it'd be great if you could post the Request Headers, Payload, and Response of the HTTP request that fetches the channels list. You can do that by using the Network Tab of the Chrome Developers Console. It is a request to this endpoint: https://content.googleapis.com/youtube/v3/channels.

I'd like to see the differences between a request that correctly fetches the channel ID ID1, and the request that correctly fetches the channel ID ID2, after you clear the cache.

Would you mind doing that instead? It'd help me as I can't manage to actually fetch the ID2 with my account. Thanks!

@TMSCH Alright so I start off with the cache cleared and access revoked. I then select my first channel account. It comes back with this:

General
Request URL:https://content.googleapis.com/youtube/v3/channels?mine=true&part=contentDetails%2Csnippet&key=AIzaSyA1_1slyqna6jI_Aj4XdSDbsgugJuEL-r0
Request Method:GET
Status Code:200
Remote Address:[2607:f8b0:4009:802::200a]:443
Referrer Policy:no-referrer-when-downgrade

Response Headers
alt-svc:quic=":443"; ma=2592000; v="37,36,35"
cache-control:private, max-age=300, must-revalidate, no-transform
content-encoding:gzip
content-length:545
content-type:application/json; charset=UTF-8
date:Wed, 26 Apr 2017 01:40:57 GMT
etag:"m2yskBQFythfE4irbTIeOgYYfBU/XWjGyeTX5jkeR8HTLkp4PeVeMkw"
expires:Wed, 26 Apr 2017 01:40:57 GMT
server:GSE
status:200
vary:Origin
vary:X-Origin
x-content-type-options:nosniff
x-frame-options:SAMEORIGIN
x-xss-protection:1; mode=block

Request Headers
Provisional headers are shown
Authorization:Bearer ya29......h7VBr
Referer:https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.g0SsD3nZybw.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCNy9nhO1CNK4nx_ImBk80FYyCM9Ig
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
X-ClientDetails:appVersion=5.0%20(Windows%20NT%2010.0%3B%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F57.0.2987.133%20Safari%2F537.36&platform=Win32&userAgent=Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F57.0.2987.133%20Safari%2F537.36
X-Goog-Encode-Response-If-Executable:base64
X-JavaScript-User-Agent:google-api-javascript-client/1.1.0-beta
X-Origin:http://www.brockkeasler.com
X-Referer:http://www.brockkeasler.com
X-Requested-With:XMLHttpRequest

Query String Parameters
view source
view URL encoded
mine:true
part:contentDetails,snippet
key:AIzaSyA1_1slyqna6jI_Aj4XdSDbsgugJuEL-r0

RESPONSE

{
 "kind": "youtube#channelListResponse",
 "etag": "\"m2yskBQFythfE4irbTIeOgYYfBU/XWjGyeTX5jkeR8HTLkp4PeVeMkw\"",
 "pageInfo": {
  "totalResults": 1,
  "resultsPerPage": 1
 },
 "items": [
  {
   "kind": "youtube#channel",
   "etag": "\"m2yskBQFythfE4irbTIeOgYYfBU/cqANoml_msDIlsy3eBelmq7ej4g\"",
   "id": "UCKuMjQdUHpsDWlVYeziYkVQ",
   "snippet": {
    "title": "ecouniversity",
    "description": "",
    "publishedAt": "2010-11-28T09:20:20.000Z",
    "thumbnails": {
     "default": {
      "url": "https://yt3.ggpht.com/-A1raocpC580/AAAAAAAAAAI/AAAAAAAAAAA/nD1YUXDhsV8/s88-c-k-no-mo-rj-c0xffffff/photo.jpg"
     },
     "medium": {
      "url": "https://yt3.ggpht.com/-A1raocpC580/AAAAAAAAAAI/AAAAAAAAAAA/nD1YUXDhsV8/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
     },
     "high": {
      "url": "https://yt3.ggpht.com/-A1raocpC580/AAAAAAAAAAI/AAAAAAAAAAA/nD1YUXDhsV8/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
     }
    },
    "localized": {
     "title": "ecouniversity",
     "description": ""
    }
   },
   "contentDetails": {
    "relatedPlaylists": {
     "likes": "LLKuMjQdUHpsDWlVYeziYkVQ",
     "favorites": "FLKuMjQdUHpsDWlVYeziYkVQ",
     "uploads": "UUKuMjQdUHpsDWlVYeziYkVQ",
     "watchHistory": "HL",
     "watchLater": "WL"
    }
   }
  }
 ]
}

At this point I revoke access and clear my cache. I sign in again, this time with my second channel account. (Same overarching google account which contains both channel accounts... not sure what to call that). It comes back with this:

General
Request URL:https://content.googleapis.com/youtube/v3/channels?mine=true&part=contentDetails%2Csnippet&key=AIzaSyA1_1slyqna6jI_Aj4XdSDbsgugJuEL-r0
Request Method:GET
Status Code:200
Remote Address:[2607:f8b0:4009:802::200a]:443
Referrer Policy:no-referrer-when-downgrade

Response Headers
alt-svc:quic=":443"; ma=2592000; v="37,36,35"
cache-control:private, max-age=300, must-revalidate, no-transform
content-encoding:gzip
content-length:547
content-type:application/json; charset=UTF-8
date:Wed, 26 Apr 2017 01:44:26 GMT
etag:"m2yskBQFythfE4irbTIeOgYYfBU/FwlSH5h6gmDqZVhUBWLYfxrbaDc"
expires:Wed, 26 Apr 2017 01:44:26 GMT
server:GSE
status:200
vary:Origin
vary:X-Origin
x-content-type-options:nosniff
x-frame-options:SAMEORIGIN
x-xss-protection:1; mode=block

Request Headers
Provisional headers are shown
Authorization:Bearer ya29.Gls4.......EpjpVTt
Referer:https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.g0SsD3nZybw.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCNy9nhO1CNK4nx_ImBk80FYyCM9Ig
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
X-ClientDetails:appVersion=5.0%20(Windows%20NT%2010.0%3B%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F57.0.2987.133%20Safari%2F537.36&platform=Win32&userAgent=Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F57.0.2987.133%20Safari%2F537.36
X-Goog-Encode-Response-If-Executable:base64
X-JavaScript-User-Agent:google-api-javascript-client/1.1.0-beta
X-Origin:http://www.brockkeasler.com
X-Referer:http://www.brockkeasler.com
X-Requested-With:XMLHttpRequest

Query String Parameters
view source
view URL encoded
mine:true
part:contentDetails,snippet
key:AIzaSyA1_1slyqna6jI_Aj4XdSDbsgugJuEL-r0

RESPONSE

{
 "kind": "youtube#channelListResponse",
 "etag": "\"m2yskBQFythfE4irbTIeOgYYfBU/FwlSH5h6gmDqZVhUBWLYfxrbaDc\"",
 "pageInfo": {
  "totalResults": 1,
  "resultsPerPage": 1
 },
 "items": [
  {
   "kind": "youtube#channel",
   "etag": "\"m2yskBQFythfE4irbTIeOgYYfBU/HPf9rxeoCPPOUp24r0PM1sAoRJA\"",
   "id": "UCPQH92IAQHnQjmI98lF7OGg",
   "snippet": {
    "title": "fieyr2002",
    "description": "",
    "publishedAt": "2006-08-04T11:55:28.000Z",
    "thumbnails": {
     "default": {
      "url": "https://yt3.ggpht.com/-mNHjPHOClz8/AAAAAAAAAAI/AAAAAAAAAAA/qpqcO2L9Xvc/s88-c-k-no-mo-rj-c0xffffff/photo.jpg"
     },
     "medium": {
      "url": "https://yt3.ggpht.com/-mNHjPHOClz8/AAAAAAAAAAI/AAAAAAAAAAA/qpqcO2L9Xvc/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
     },
     "high": {
      "url": "https://yt3.ggpht.com/-mNHjPHOClz8/AAAAAAAAAAI/AAAAAAAAAAA/qpqcO2L9Xvc/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
     }
    },
    "localized": {
     "title": "fieyr2002",
     "description": ""
    }
   },
   "contentDetails": {
    "relatedPlaylists": {
     "likes": "LLPQH92IAQHnQjmI98lF7OGg",
     "favorites": "FLPQH92IAQHnQjmI98lF7OGg",
     "uploads": "UUPQH92IAQHnQjmI98lF7OGg",
     "watchHistory": "HL",
     "watchLater": "WL"
    }
   }
  }
 ]
}

As you can see, the channel ids are different. However if I hadn't cleared the cache half way through, the second id returned in the response for account 2 would have been the same as account 1.

@TMSCH Let me know if you need more than this. I'm not used to using the network tab, so feel free to ask for anything if I missed something.

@TMSCH I discovered something interesting. So let's say I login to one channel, see that it's authenticated, and see that I'm getting the correct channel id. When I sign into another channel... I've needed to clear the cache first right? Well today I discovered that if I wait 3-5 minutes after revoking permissions on the first channel before attempting to sign into the second channel... it actually will sign into the second channel successfully... correct id and everything.

At first I thought... maybe this is something to do with the oauth server taking some time to revoke which is mentioned in the docs online. But then it doesn't make sense that I can instantly login to the second channel if I just clear my browser cache. This makes me think there's actually something being stored locally that expires after a set time.

@fieyr @flawiddsouza thanks for all the information. We have a lead on what the cause of the issue could be, we are investigating a fix. I'll keep this thread updated.

@TMSCH Thanks for the update and working so hard to figure this out. As always, let me know if you need any additional info.

@fieyr I am having the exact same issue as yourself - I've recently posted a Stackoverflow question with what I am experiencing: https://stackoverflow.com/questions/44586779/youtube-channel-id-isnt-being-updated-after-signin-via-google-api-firebase

Have you managed to figure out a solution?

@sutsurikeru1986 - No, still waiting for a fix or solution of some sort. :(

@fieyr That sucks, any update regarding this @TMSCH?

@sutsurikeru1986 @fieyr I apologize for the delay, the relevant team is still working on a fix.

@TMSCH - Any ETA on a fix? Or is the relevant team stumped at the moment? I'd like to know just so I can make a decision on how to proceed.

@fieyr I don't have any ETA yet, the team seems pretty busy. However, please note that the response is cached 300 seconds, i.e. 5 minutes, after which the new call will return the correct Channel ID.

@fieyr @sutsurikeru1986 there actually is a work around. The issue is that the HTTP requests fetching the channels is cached by the browser. While waiting on a fix, you can use batch requests instead of the usual gapi.client.request, that will perform a POST request instead of a GET request and will not use the cache.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Nilesh-P picture Nilesh-P  ยท  4Comments

wonderfly picture wonderfly  ยท  3Comments

lucasriondel picture lucasriondel  ยท  3Comments

phyllisstein picture phyllisstein  ยท  3Comments

nmquaan-bigbom picture nmquaan-bigbom  ยท  7Comments