New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sporadic "Invalid Credentials" Issues - Service Account #1075
Comments
When you say "sporadic" do you mean after 3600 seconds? That would be the time when the access token is expired and you would have to get a new one. I am having the same issue and i do understand that it is due to the expired access token. This is my particular code sequence (which is quite similar to yours): /* This env variable holds the path to the keyfile with the JSON based certificate. It will be required by the Google API Client */
putenv( 'GOOGLE_APPLICATION_CREDENTIALS=' . $objApplication->getConfig( 'App::GoogleAuthServiceAccoutKeyAsJson' ) );
try{
/* Using Stash for caching */
//$objCache = new Pool( new FileSystem );
//$objCacheLogger = new Logger;
//$hdTokenCallback = function( $cacheKey, $accessToken ) use ( $objCacheLogger ) {
// $objCacheLogger->debug( sprintf( 'A new access token \'%s\' has beeen received for the cache key %s', $accessToken, $cacheKey ) );
//};
/* Creating the client */
$objGoogleApiClient = new \Google_Client();
$objGoogleApiClient->useApplicationDefaultCredentials();
$objGoogleApiClient->setApplicationName( 'myTestApplication' );
$objGoogleApiClient->setAccessType( 'offline' );
$objGoogleApiClient->setScopes( [ 'https://www.googleapis.com/auth/webmasters.readonly' ] );
//$objGoogleApiClient->setCache( $objCache );
//$objGoogleApiClient->setTokenCallback( $hdTokenCallback );
/* Refresh token when expired */
if( $objGoogleApiClient->isAccessTokenExpired() ){
$objGoogleApiClient->refreshTokenWithAssertion();
}
/* Creating the actual service */
$this->objGoogleService = new \Google_Service_Webmasters( $objGoogleApiClient );
} catch( \Google_Exception $objException ){
die(" An exception has occured!" );
} I have also diggged into what feels like the entire documentation there is in the Internet ;-). But i still get the expiration after 3600. I am as well using a service account and this code runs on the console. What am i doing wrong, why am getting the expiration? Is this part /* Refresh token when expired */
if( $objGoogleApiClient->isAccessTokenExpired() ){
$objGoogleApiClient->refreshTokenWithAssertion();
} not enough to do the refreshing? I used a debugger but could not find a refresh token passed back to Client.php, it was always null. Recreated millions of service accounts and went through the initial authentication process expecting to get one, but none which i could save away and use for later refreshing process. As opposed to omnicodagithub i am getting the 401 not sporadically but regularly after one hour. Above code is using google/apiclient v2.0.3. Thanks for any advice. |
It was the expiration. I've decided to go with OAuth instead but that's also seeming to be a nightmare to set up. Even when I copy Google's own examples they often don't seem to work or only work temporarily. |
-- Even when I copy Google's own examples they often don't seem to work or only work temporarily |
Update: |
We have the same issue with v2.0.3
We see expired access token and ~30 seconds after fetching a new access token the API responds with "Invalid Credentials". Re-initialising the client when the access token expires works as a current "dirty but worky" solution. |
@omnicodagithub I had the same issue, but I think I have a solution, @bshaffer does some checks for cache in the library prebuilt, can you try this?
|
I am looking into this. Can you provide a stack trace for the I believe the problem may be the refresh token is not being persisted in the in-memory cache. |
Changing the scopes uses a different cache key. This is almost certainly why that fixes the issue. But if you're using in-memory cache, I would think the tokens wouldn't persist enough for it to matter. |
Links to another question on stack along the same lines. Google Analytics Reporting API V4 with “Request had invalid authentication credentials” |
Just an update from me. So to test I am storing the entire access token in the database (access_key, token_type, expires_in, refresh_key and created). I am using this token from the database with the setAccessToken method. This is almost always resulting in a 401 "Invalid Credentials" error. When I test this same key in the Google API Playground it works fine, so it doesn't seem to be the access token. Not sure if I'm not quite understanding it, but if I'm using an access token from the database, then the cache shouldn't affect this should it? By the way, it did actually work earlier for a while using this method. This issue really has me scratching my head as one time it's working fine, the next it's not working. |
Thanks for the update @omnicodagithub ! Ahh how the plot thickens. Could you do two things for me please?
Set up the proxy by adding this when you create your client: $options = [
'proxy' => 'localhost:8888', // the default for charles
'verify' => false,
];
$httpClient = new GuzzleHttp\Client($options);
$client->setHttpClient($httpClient); |
Hi @bshaffer! Thanks for the help by the way. Ok, so here is the stack trace: Stack trace: Regarding point two, when using Charles I can see that a different access_token is being used for authorisation. The one I am using for setAccessToken() is definitely the correct one (I'm printing it out to the page so I can confirm). Is there a cached one and is that one being used instead of the one I'm passing to setAccessToken()? |
@omnicodagithub hmm, if you've told the Digging deeper into this, it appears that the explicitly-set Access Token bypasses the cache, and so shouldn't be affected. Is it possible you're using two different service accounts? Have you tried rolling back to |
@bshaffer looking at the github compare with a previous stable version; It seems cache is set always, in memory or filesystem if pool library is available This is why clearing works, since when you clear it makes a brand new token refresh call (which defeats the whole purpose of cache) Hope this was helpful, maybe I have some time tomorrow I can submit a pull request for the line to check if whats in cache is expired first before using it |
@bshaffer Hmm weird. I was using I added this last night, just to test, so it could be this as the reason for
Edit: I did what @chonthu suggested and I just cleared the cache. I started getting results again after that. |
You shouldn't need to manually clear the cache. This implies the cache is not invalidated properly. Looking in the code, a token being received should expire after Can you call |
To fix this in the auth library, I've added googleapis/google-auth-library-php#138, which is not ideal (the call should be unnecessary) but will get the job done. Another option would be to stop using |
I just wanted to mention that we're still seeing this error in 2.0.3 (as well as the last 1.x release). The only thing that worked was manually fetching a new access token, as mentioned above. My hack is to do that on the first 401 and retry the API call but I would obviously prefer if this just worked. Please let me know if there's anything you'd like me to provide. I can send stack traces, and I'm using the Calendar API. |
Per PSR-6: > Hit - A cache hit occurs when a Calling Library requests an Item by key and a matching value is found for that key, and that value has not expired, and the value is not invalid for some other reason. Calling Libraries SHOULD make sure to verify isHit() on all get() calls. The $cacheItem response is never validated, and in the case of the Stash library the response contains the expired data (presumably to provide access to the previous cache). This should fix a recurring issue with authentication when using Stash for storing tokens; which were never being regenerated properly. There is one open issue googleapis/google-api-php-client#1075, plus several other closed issues which appear to have misdiagnosed the issue.
I ran into this problem and have been working around it for months; finally got around to tracing down this bug. The Stash library's response appears to include expired cache data which is properly flagged as a Miss (which could be a benefit for some situations), however the Google Auth library never tests it to confirm it should be used. This pull request does a proper verification of the response; and allows us to replace hacks like the one suggested in October by @chonthu (which was clearing the entire Stash cache on every hit). My client setup code now no longer needs to test for expiration or manually refresh the tokens. |
@BVMiko while i agree with this fix because of the quote from PSR-6, it looks like stash ensures the |
Looks like I added that 8 months ago... |
Okay, I just figured out what's going on. Two weeks before your PR, a new version of Stash was finally tagged with the fix I added 8 months ago. So this is now fixed with Since the PSR-6 spec says the calling library SHOULD verify the cache hit, the changes in #150 are valid, even though the spec ALSO says Either way this issue is fixed! |
I seem to be having weird issues with "Invalid Credentials" errors, service accounts and the Search Console API. Sometimes everything works and I can access the API, then some time later I may try an access the SC API and I get an "Invalid Credentials" error. This is without changing any code.
Edit: Very weird. I swapped around my scopes and then it started working again. Nothing else was changed. Why would swapping my scopes around every so often work?
Here is what I am using:
The weird thing is it works sometimes. Is this some sort of bug? I've followed pretty much every tutorial out there about service accounts and this API client, but it still seems to be quite random as to why sometimes I can use the API and other times I get an "Invalid Credentials" error.
The text was updated successfully, but these errors were encountered: