23

I'm facing problem with Google push notifications (for drive). I use service account which works perfectly for all other drive operations except drive changes watch.

Below is application code which now fails with "Unauthorized WebHook callback channel" exception. I also dumped requests and responses which are generated when drive.changes.watch.execute is called.

Target notification address is whitelisted in APIs & auth Push control panel (I even listed it in Javascript origins and referrers) and now I'm stuck with this 401 Unauthorized error.

Does someone know where I'm making mistake? Thanks for any help.

PrivateKey serviceAccountPrivateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), p12File, "notasecret", "privatekey", "notasecret");
JsonFactory jsonFactory = new JacksonFactory();
HttpTransport t = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential gc = new GoogleCredential.Builder()
                .setTransport(t)
                .setJsonFactory(jsonFactory)
                .setServiceAccountScopes(Collections.singleton(DriveScopes.DRIVE))
                .setServiceAccountPrivateKey(serviceAccountPrivateKey)
                .setServiceAccountId(Config.SERVICE_ACCOUNT_ID)
                .setServiceAccountUser(Config.SERVICE_ACCOUNT_USER)
                .build();

drive = new Drive.Builder(t, jsonFactory, null).setHttpRequestInitializer(gc).setApplicationName(cfg.getStringParam(Config.GAE_APPLICATION_NAME)).build();

// THIS WORKS
Changes.List request = drive.changes().list();
ChangeList changes = request.execute();

// THIS DOES NOT WORK
Channel channel = new Channel();
channel.setId(UUID.randomUUID().toString());
channel.setType("web_hook");
channel.setAddress(Config.PUSH_NOTIFICATION_ADDRESS);
Channel c = drive.changes().watch(channel).execute();


-------------- REQUEST  --------------
POST https://www.googleapis.com/drive/v2/changes/watch
Accept-Encoding: gzip
Authorization: Bearer XXX
User-Agent: XXX Google-HTTP-Java-Client/1.17.0-rc (gzip)
Content-Type: application/json; charset=UTF-8
Content-Length: 118

CONFIG: curl -v --compressed -X POST -H 'Accept-Encoding: gzip' -H 'Authorization: Bearer XXX' -H 'User-Agent: XXX Google-HTTP-Java-Client/1.17.0-rc (gzip)' -H 'Content-Type: application/json; charset=UTF-8' -d '@-' -- 'https://www.googleapis.com/drive/v2/changes/watch' << $$$
CONFIG: {"address":"XXX","id":"8078114c-fba0-44e7-a34c-cb391ea40061","type":"web_hook"}

-------------- RESPONSE --------------
401 OK
www-authenticate: Bearer realm="https://accounts.google.com/AuthSubRequest", error=invalid_token

-------------- REQUEST  --------------
POST https://accounts.google.com/o/oauth2/token

-------------- RESPONSE --------------
200 OK
{
  "access_token" : XXX,
  "token_type" : "Bearer",
  "expires_in" : 3600
}

-------------- REQUEST  --------------
POST https://www.googleapis.com/drive/v2/changes/watch

-------------- RESPONSE --------------
401 OK
www-authenticate: Bearer realm="https://accounts.google.com/AuthSubRequest", error=invalid_token

...
...
...

-------------- RESPONSE --------------
200 OK
content-type: application/json; charset=utf-8
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Fri, 01 Jan 1990 00:00:00 GMT
date: Wed, 28 May 2014 20:51:19 GMT
content-disposition: attachment; filename="json.txt"; filename*=UTF-8''json.txt
content-encoding: gzip
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
server: GSE
alternate-protocol: 443:quic
transfer-encoding: chunked

{
  "access_token" : XXX,
  "token_type" : "Bearer",
  "expires_in" : 3600
}

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "push.webhookUrlUnauthorized",
    "message": "Unauthorized WebHook callback channel: XXX"
   }
  ],
  "code": 401,
  "message": "Unauthorized WebHook callback channel: XXX"
 }
}
user3686724
  • 603
  • 1
  • 5
  • 15
  • Half year after, same code, same configuration, same environment, domain, etc. and now it works... – user3686724 Nov 25 '14 at 15:40
  • 3
    FWIW, I was getting this error today. The Domain Verification was not saving in google developer console (refresh the page and it was gone). The problem ultimately ended up being I was logged in as two google accounts, my gmail account and my company account. Adding the domain verification seemed to get confused about the account and not save the domain settings. Hope this helps somebody. – John Naegle Mar 03 '16 at 04:13
  • @JohnNaegle This was the solution that worked for me. Thanks :-) – Atihska Sep 07 '16 at 21:01
  • @JohnNaegle Wow. Yeah, refresh and everything is gone. ( that took an hour and half to diagnose ). Thank god for your comment. I've tried relogging and incognito, same result => No real save seems to happen. Was there something you did in particular? – Peege151 Jan 20 '17 at 08:05
  • @Peege151 I don't remember now - sorry. The google developer console is a very frustrating tool. – John Naegle Jan 20 '17 at 14:28
  • @user3686724, I've got similar issue. Have you solved one? Can you share your solution, please? – Sergii Feb 06 '17 at 09:36
  • As i wrote earlier, under same conditions it did work later (it was 11/2014), but as I am not using that code any more I can't tell what is the problem now... – user3686724 Feb 07 '17 at 09:02
  • I also have this issue. I tried incognito, and nothing seems to work. Adding comment here in case anyone has a solution – theawesome Mar 12 '17 at 11:14
  • I am also getting same problem, I am using angular5 and nodejs app. – Girish Rathod Jul 06 '18 at 10:56
  • I am getting this issue as well... I have the URL saved and verified but still get the 401 Unauthorized error. – Dario Macieira May 13 '20 at 02:23

6 Answers6

32

You have to add your domain to the developers console.

How to:

  1. Log in to the Google Developers Console
  2. Select your project
  3. Under 'APIS & AUTH' select 'Push'
  4. Click 'Add domains'
  5. Enter the needed domains (Only the domain is needed, not the whole notification url)
  6. Click the 'Add domains' button

After that it should work unless there's something else wrong with what you're doing :p

natronite
  • 858
  • 8
  • 23
  • 4
    You also need to add a https url, and have a valid (not self-signed) SSL license. – Sire Oct 29 '15 at 16:07
  • 14
    APIS & AUTH has moved to Credentials => Domain Verification – John Naegle Mar 03 '16 at 04:12
  • 7
    Sounds like an obvious thing - but this didn't work for me for ages because the test access token I was getting was tied to the OAuth playground app, not my own Google app (where I'd added the domain as above). – Chris Houghton Apr 13 '16 at 23:19
  • 1
    I have this working on production, do you know any way to test it locally though? – gdvalderrama Sep 27 '17 at 17:21
  • The only way you could test notifications locally would be if your machine had a dedicated IP that Google can access through a domain. You can add localhost in the developer console to use the API locally though. Refer to this thread: [How to test google calendar api v3 on localhost](https://stackoverflow.com/questions/26982040/how-to-test-google-calendar-api-v3-on-localhost#answer-31363934) – natronite Sep 28 '17 at 06:21
  • 1
    The steps are now: 1. Go to the Google Cloud Platform Console. 2. Select your project. 3. Open the navigation sidebar in the top left corner, select APIs & services. 4. Then select Credentials. Select Domain verification. 5. Select Add domain. – Shaun Dec 19 '18 at 00:49
5

For me, as I put in a comment above,

The Domain Verification was not saving in google developer console (refresh the page and it was gone). The problem ultimately ended up being I was logged in as two google accounts, my gmail account and my company account. Adding the domain verification seemed to get confused about the account and not save the domain settings.

Try logging in using a different browser or incognito session if you use multiple google accounts.

John Naegle
  • 8,077
  • 3
  • 38
  • 47
3

So this is all because of Settings on console.developers.google.com. You need to add your back-end domain to both Authorised domains on (OAuth Consent Screen tab) and Allowed domains (on Domain Verification tab).

So there reason why it works for you now is that probably you verified and added your top-level domain already while your local environment had separate (not a sub domain of the verified top-level) domain at the time, specially if you had been exposing your local server on internet.

0

For me, I wanted the callback webhook URL as https://test-apis.domain.io. So for domain verification, I added test-apis.domain.io and then tried to modify the TXT record but it never was working(validating).

Finally ended up verifying just domain.io with the same method. After this was done I was able to add the domain test-apis.domain.io in the credentials "Domain verification" screen. Hope this helps others as well.

Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
0

I confirmed my domain, checked my SSL, but problem hasn't gone.

Finally I found the solution: Use Service Acconut Key in Google Developers Console (not API Key and not OAuth client ID).

Valdi_Bo
  • 30,023
  • 4
  • 23
  • 41
0

I had this same issue. Other answers mention the need to add your domain to Google Cloud Platform Console -> APIs & Services -> Domain verification. Where I went wrong was I had a route attached to my domain so I was trying to add https://www.example.com/route. Needed to verify ownership of the top-level domain, ie of https://www.example.com in Google Search Console, then add top-level domain in domain verification and then could use https://www.example.com/route as the address in drive.changes.watch().

JBW
  • 63
  • 8