title: Google push notifications - Unauthorized WebHook callback channel
body: <p>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. </p>
  
  <p>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.</p>
  
  <p>Target notification address is whitelisted in APIs &amp; auth Push control panel (I even listed it in Javascript origins and referrers) and now I'm stuck with this 401 Unauthorized error.</p>
  
  <p>Does someone know where I'm making mistake? Thanks for any help. </p>
  
  <pre><code>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' &lt;&lt; $$$
  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"
   }
  }
  </code></pre>