Skip to content

Instantly share code, notes, and snippets.

@rithvikvibhu
Last active November 20, 2024 02:38
Show Gist options
  • Save rithvikvibhu/952f83ea656c6782fbd0f1645059055d to your computer and use it in GitHub Desktop.
Save rithvikvibhu/952f83ea656c6782fbd0f1645059055d to your computer and use it in GitHub Desktop.
Get tokens for Google Home Foyer API

Get tokens for Google Home Foyer API

Intro

This script (python 3) generates tokens that can be used when making requests to the Google Home Foyer API. There are 2 kinds of tokens used here:

  1. Master token - Is in the form aas_et/*** and is long lived. Needs Google username and password.
  2. Access token - Is in the form ya29.*** and lasts for an hour. Needs Master token to generate.

If you do not want to store the Google account password in plaintext, get the master token once, and set it as an override value.

It's safer/easier to generate an app password and use it instead of the actual password. It still has the same access as the regular password, but still better than using the real password while scripting. (https://myaccount.google.com/apppasswords)

Usage

# Install python requirements
pip install gpsoauth

# Update the constants at the beginning of the file

# Get the tokens!
python3 get_tokens.py
# Get tokens for Google Home Foyer API
# https://gist.github.com/rithvikvibhu/952f83ea656c6782fbd0f1645059055d
from gpsoauth import perform_master_login, perform_oauth
from uuid import getnode as getmac
# Creds to use when logging in
USERNAME = '<google_username>'
PASSWORD = '<google_password_or_app_password>'
# Optional Overrides (Set to None to ignore)
device_id = None
master_token = None
access_token = None
# Flags
DEBUG = False
def get_master_token(username, password, android_id):
res = perform_master_login(username, password, android_id)
if DEBUG:
print(res)
if 'Token' not in res:
print('[!] Could not get master token.')
return None
return res['Token']
def get_access_token(username, master_token, android_id):
res = perform_oauth(
username, master_token, android_id,
app='com.google.android.apps.chromecast.app',
service='oauth2:https://www.google.com/accounts/OAuthLogin',
client_sig='24bb24c05e47e0aefa68a58a766179d9b613a600'
)
if DEBUG:
print(res)
if 'Auth' not in res:
print('[!] Could not get access token.')
return None
return res['Auth']
def _get_android_id():
mac_int = getmac()
if (mac_int >> 40) % 2:
raise OSError("a valid MAC could not be determined."
" Provide an android_id (and be"
" sure to provide the same one on future runs).")
android_id = _create_mac_string(mac_int)
android_id = android_id.replace(':', '')
return android_id
def _create_mac_string(num, splitter=':'):
mac = hex(num)[2:]
if mac[-1] == 'L':
mac = mac[:-1]
pad = max(12 - len(mac), 0)
mac = '0' * pad + mac
mac = splitter.join([mac[x:x + 2] for x in range(0, 12, 2)])
mac = mac.upper()
return mac
if not device_id:
device_id = _get_android_id()
print('''
This script generates tokens that can be used when making requests to the Google Home Foyer API.
There are 2 kinds of tokens used here:
1. Master token - Is in the form `aas_et/***` and is long lived. Needs Google username and password.
2. Access token - Is in the form `ya29.***` and lasts for an hour. Needs Master token to generate.
If you do not want to store the Google account password in plaintext,
get the master token once, and set it as an override value.
It's safer/easier to generate an app password and use it instead of the actual password.
It still has the same access as the regular password, but still better than using the real password while scripting.
(https://myaccount.google.com/apppasswords)
''')
print('\n[*] Getting master token...')
if not master_token:
master_token = get_master_token(USERNAME, PASSWORD, device_id)
print('[*] Master token:', master_token)
print('\n[*] Getting access token...')
if not access_token:
access_token = get_access_token(USERNAME, master_token, device_id)
print('[*] Access token:', access_token)
print('\n[*] Done.')
MIT License
Copyright (c) 2020 Rithvik Vibhu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@BimpArno
Copy link

or can someone explain how to do that docker

Since there are several issues getting the token reliable on different environments, you can use a docker container which was created solely for this use: https://hub.docker.com/r/breph/ha-google-home_get-token. If you choose to use this container, run the following command:

$ docker run --rm -it breph/ha-google-home_get-token

i have no clue what to do here

@edx-sayed-salem
Copy link

@BimpArno you can edit get_tokens.py of the docker image you linked and rebuild it with its Dockerfile, it's all here I believe. Add the lines from a few comments ago. If it is that same issue, it should work.

@totoantibes
Copy link

@BimpArno you can edit get_tokens.py of the docker image you linked and rebuild it with its Dockerfile, it's all here I believe. Add the lines from a few comments ago. If it is that same issue, it should work.

so the Dockerfile worked, but i had to add import os to the get_tokens.py working so now it looks like this:

# Get tokens for Google Home Foyer API
# https://gist.github.com/rithvikvibhu/952f83ea656c6782fbd0f1645059055d


from gpsoauth import perform_master_login, perform_oauth
from uuid import getnode as getmac

import urllib.request
import os 
# Download the SSL certificate
urllib.request.urlretrieve('https://curl.se/ca/cacert.pem', 'cacert.pem')

# Set downloaded cert to be used
os.environ['CURL_CA_BUNDLE'] = f'{os.getcwd()}/cacert.pem'


# Creds to use when logging in
USERNAME = 'example@gmail.com'
PASSWORD = 'yourpassword'

# Optional Overrides (Set to None to ignore)
device_id = None
master_token = None
access_token = None

# Flags
DEBUG = True

def get_master_token(username, password, android_id):
    res = perform_master_login(username, password, android_id)
    if DEBUG:
        print(res)
    if 'Token' not in res:
        print('[!] Could not get master token.')
        return None
    return res['Token']


def get_access_token(username, master_token, android_id):
    res = perform_oauth(
        username, master_token, android_id,
        app='com.google.android.apps.chromecast.app',
        service='oauth2:https://www.google.com/accounts/OAuthLogin',
        client_sig='24bb24c05e47e0aefa68a58a766179d9b613a600'
    )
    if DEBUG:
        print(res)
    if 'Auth' not in res:
        print('[!] Could not get access token.')
        return None
    return res['Auth']


def _get_android_id():
    mac_int = getmac()
    if (mac_int >> 40) % 2:
        raise OSError("a valid MAC could not be determined."
                      " Provide an android_id (and be"
                      " sure to provide the same one on future runs).")

    android_id = _create_mac_string(mac_int)
    android_id = android_id.replace(':', '')
    return android_id


def _create_mac_string(num, splitter=':'):
    mac = hex(num)[2:]
    if mac[-1] == 'L':
        mac = mac[:-1]
    pad = max(12 - len(mac), 0)
    mac = '0' * pad + mac
    mac = splitter.join([mac[x:x + 2] for x in range(0, 12, 2)])
    mac = mac.upper()
    return mac


if not device_id:
    device_id = _get_android_id()
    print(device_id)


print('''
This script generates tokens that can be used when making requests to the Google Home Foyer API.
There are 2 kinds of tokens used here:

1. Master token - Is in the form `aas_et/***` and is long lived. Needs Google username and password.
2. Access token - Is in the form `ya29.***` and lasts for an hour. Needs Master token to generate.

If you do not want to store the Google account password in plaintext,
get the master token once, and set it as an override value.

It's safer/easier to generate an app password and use it instead of the actual password.
It still has the same access as the regular password, but still better than using the real password while scripting.
(https://myaccount.google.com/apppasswords)
''')

print('\n[*] Getting master token...')
if not master_token:
    master_token = get_master_token(USERNAME, PASSWORD, device_id)
print('[*] Master token:', master_token)

print('\n[*] Getting access token...')
if not access_token:
    access_token = get_access_token(USERNAME, master_token, device_id)
print('[*] Access token:', access_token)

print('\n[*] Done.')

@Th0tti
Copy link

Th0tti commented Oct 28, 2024

How can I delete or overwrite the master token?

@Maxver0
Copy link

Maxver0 commented Nov 15, 2024

This script doesn't seem to work.

Updated the script's username and password variables. Tried full email, just the username, normal password, the app password. For the app password, I'd remove the spaces and any extra characters but no luck.

HA Integration throws the same error.

[] Getting master token...
{'Error': 'BadAuthentication'}
[!] Could not get master token.
[
] Master token: None

[] Getting access token...
{'Error': 'BadAuthentication'}
[!] Could not get access token.
[
] Access token: None

@ktfcaptain
Copy link

Just spent way too long trying to get this working with no success

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment