Skip to content

Instantly share code, notes, and snippets.

Forked from rithvikvibhu/
Last active Jul 26, 2019
What would you like to do?
GHLocalApi Update

GHLocalApi Update

The Gist

Until recently, the Google Home app used to communicate with the device over port 8008 (HTTP) and did not require any authentication. Everything in the unofficial documentation worked as expected.

A few days (weeks) ago, Google pushed a new update to all GH devices and all endpoints (except /setup/eureka_info) started returning 403 (forbidden) errors. The app had switched over to port 8443 and HTTPS.

The Fix

Lots happened over at #39. Finally, the only changes required are:

  • Change port from 8008 to 8443
  • Change protocol from http to https
  • Add a new header (for all requests) cast-local-authorization-token

Note: Since this is https, the CA will likely not be trusted by your device. "Enable Insecure Requests" or "Allow Self Signed Certificates" when making requests. For example, pass the -k/--insecure flag with curl and verify=False with python's requests.

The Token

The token required for cast-local-authorization-token can be obtained by 2 methods. As of now, I'm not sure if this token expires or when it does or even how the app gets it in the first place.

/TODO: Add more info

Getting the token

2 ways: From app data directory on android or with Frida.

Both require root. First one recommended.

App Data Dir (Android)

This extracts the token from the app's data folder. The script finds tokens of all devices which might have this token. Only NodeJs is required, a browser friendly page coming soon.

  • With a root file manager, pull this file: /data/data/*.proto
  • Run node decodeProtoFile.js <file> to extract tokens. (script attached)

With Frida (Android)

Frida injects and hooks onto running applications. The script logs all requests along with the needed header.

  • Install and set up Frida and ADB
  • Connect the phone to PC and copy Frida Server
  • Open the Google Home app on the phone
  • Use this script (thanks @TheKalin!)
  • Open GH settings in the app. The header with token will be printed.
const fs = require('fs');
const util = require('util');
const rawproto = require('rawproto');
const filename = process.argv[2] || 'home_graph.pb';
console.log(`[*] Reading proto binary... (${filename})`)
var buffer = fs.readFileSync(filename)
console.log(`[*] Parsing file...`)
var data = rawproto.getData(buffer);
// detailedLog(data);
console.log('[*] Extracting token...\n')
data.forEach(val => {
if (val['2'] && Array.isArray(val['2'])) {
val['2'].forEach(val2 => {
try {
if (val2['7'] && Array.isArray(val2['7'])) {
var device = getObjByKey(val2['7'], '17')['17'][0]['2'] + ', ' + getObjByKey(val2['7'], '18')['18'][0]['2']
var token = getObjByKey(val2['7'], '28')['28'];
console.log('Device:\t', device)
console.log('Token:\t', token)
} catch (e) {}
function detailedLog(obj) {
console.log(util.inspect(obj, {showHidden: false, depth: null}))
function getObjByKey(arr, key) {
return arr.filter(v => v[key])[0]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment