Reputation: 33
I've been struggling with this issue since yesterday. Looked for solutions that helped other people who faced similar problem, but nothing is working for me. I will appreciate if somebody could help me!
I've created a project (name: xxx), with app engine (id: app-xxx) that watches a GCS bucket (name: bucket-xxx). App engine and bucket are in the same project. I tried following the steps listed here:
Created service account (email: [email protected]) with p12 key.
Whitelisted URL (property: https: //app-xxx.appspot.com). I see the URL listed in webmaster search console. The same is also listed when I use webmaster list API.
Registered domain (app-xxx.appspot.com/)
Configured gsutil to use the service account "gcloud auth activate-service-account [email protected] --key-file path/to/key.p12". Verified with "gcloud auth list" command, which reports:
Credentialed accounts: - [email protected] (active)
I see permissions listed in Permissions page in developers console: [email protected] (App Engine service account)
I can also successfully upload files from local machine to GCS bucket-xxx: "gsutils cp local-file gs://bucket-xxx/"
However, when I setup notification, it reports: "ServiceException: 401 Unauthorized WebHook callback channel: https://app-xxx.appspot.com/notification"
The received response header shows the following error: "WWW-Authenticate: Bearer realm="https://accounts.google.com/", error=invalid_token"
Any ideas what could be wrong here? Thanks!
Upvotes: 2
Views: 2766
Reputation: 11
Just to expand on Sevle's answer: This also happens even if you retrieve the credentials for the default application service account from (for instance) Secret Manager and then create a client from them.
In a Firebase project written in TypeScript I had to change my code from:
return google.auth.getClient({
credentials,
scopes: ['https://www.googleapis.com/auth/calendar'],
})
.then((client) => {
client.subject = settings.get('apiUser');
return google.calendar({
version: 'v3',
auth: client,
});
});
to instead work like this:
return new GoogleAuth({
scopes: ['https://www.googleapis.com/auth/calendar'],
clientOptions: { subject: settings.get('apiUser') },
}).getClient()
.then((client) =>
google.calendar({
version: 'v3',
auth: client,
})
);
Note that the google
in google.auth.getClient
from the first example is bundled with the package googleapis
on npm, but the new GoogleAuth
used in the second example actually comes from google-auth-library
.
We changed the app architecture slightly so we don't need different service accounts on different requests, so this works for us now.
Upvotes: 0
Reputation: 6015
It looks like there may be an issue when you specify a webhook for an App Engine application using a Service Account that is not the application's default service account credentials (ie. one that you create yourself, that is not [email protected]). Since there's no way to get the p12 key for this account, you won't be able to add the watch using gsutil.
What you would need to do is add the watch from inside the App Engine application itself, using the JSON API and the application's default service account credentials (AppAssertionCredentials). Here's an incomplete Python example (my default since I don't know which language your app uses) which shows how this might be accomplished which uses the google-api-python-client:
from oauth2client.appengine import AppAssertionCredentials
from httplib2 import Http
from apiclient.discovery import build
credentials = AppAssertionCredentials('https://www.googleapis.com/auth/devstorage.read_only')
http_auth = credentials.authorize(Http())
storage = build('storage', 'v1', http=http_auth)
request = service.objects().watchAll(bucket='mybucket', body={args...})
request.execute()
See the pydoc for watchAll. Note you'll need to add the application's default Service Account to the bucket's ACLs for this to work (which is almost always [email protected], viewable in the 'Permissions' section of the Developer Console).
Upvotes: 4