Skip to content

Instantly share code, notes, and snippets.

@rithvikvibhu
Last active June 7, 2023 12:16
Embed
What would you like to do?
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.
@cicero200272
Copy link

I am requested to log in (using a browser) first. When I copy & paste the URL to a browser window, I can provide my credentials, but then I am stuck on a "One moment please..." page which does not reload. Does anybody else have this kind of problem?

@rithvikvibhu
Copy link
Author

Not sure what you mean @cicero200272. Which URL did you copy? This script doesn't need any browser or a website to visit at all.

@cicero200272
Copy link

screen1

@rithvikvibhu
Copy link
Author

@cicero200272 Let's move to an issue rithvikvibhu/GHLocalApi#71

@ArnyminerZ
Copy link

Thank you, @rithvikvibhu.

I have written a small script in python that is extracting the local authentication tokens.
https://github.com/leikoilja/glocaltokens.

If helpful you can maybe include it in the https://rithvikvibhu.github.io/GHLocalApi/ documentation :)

Just wanted to thank you very much for your work. Loading the device's JSON had me crazy for some days :)

@Shonke
Copy link

Shonke commented Dec 13, 2022

@ArnyminerZ After investigation, i found that this may be related to tls fingerprints. I use this to work for me:
https://github.com/akinazuki/google_aas_et_generate/blob/84c6ca6/aas_et.go#L41

@bagelos
Copy link

bagelos commented Mar 6, 2023

Hi
I am getting a weird error running this - whilst trying to resolve goog-home integration with homeassistant.

Ubuntu 22.04 and python 3.11. Latest available @ 2023-Mar-06

Traceback (most recent call last):
File "/home/homeassistant/get_tokens.py", line 70, in
device_id = _get_android_id()
^^^^^^^^^^^^^^^^^
File "/home/homeassistant/get_tokens.py", line 49, in _get_android_id
raise OSError("a valid MAC could not be determined."
OSError: a valid MAC could not be determined. Provide an android_id (and be sure to provide the same one on future runs).

I have used two different app passwords. One where I select Device Other first (and then no option to choose app is available), or app as Other (and then no optiion to choose device).

Versions are :
glocaltokens==0.7.0
gpsoauth==1.0.2
requests==2.28.2
requests-toolbelt==0.10.1
urllib3==1.26.14

If I try a random device_id, I cannot authenticate. Results below.

[] Getting master token...
[!] Could not get master token.
[
] Master token: None

[] Getting access token...
[!] Could not get access token.
[
] Access token: None

thanks
gb

@leikoilja
Copy link

@bagelos, this is wrong place for your issue. What you are seeing is the validation error from glocaltokens library. Please open a new issue ticket here https://github.com/leikoilja/glocaltokens

@bagelos
Copy link

bagelos commented Mar 6, 2023

thanks. will try that. was wondering if the inablity to pick up MAC address was an issue with this script or not.

@jcarlyle
Copy link

thanks. will try that. was wondering if the inablity to pick up MAC address was an issue with this script or not.

This does not seem to be an error from glocaltokens. The call to getmac is an alias for a call to uuid.getnode and getnode is returning a value that is failing the check at line 48. This doesn't seem to involve any calls into glocaltokens.

I tried removing the check and and generating my own 48-bit integer, but I still fail to generate tokens.

Has this script worked for anyone else recently?

@artickl
Copy link

artickl commented Jun 1, 2023

Error: AttributeError: module 'urllib3.util.ssl_' has no attribute 'DEFAULT_CIPHERS'

Fixed by downgrading urllib3 as per simon-weber/gpsoauth#52

pip3 install urllib3\<=2

Before it was:

$ python3 get_tokens.py

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)


[*] Getting master token...
Traceback (most recent call last):
  File "/home/artickl/git/github/gist/get_tokens.py", line 90, in <module>
    master_token = get_master_token(USERNAME, PASSWORD, device_id)
  File "/home/artickl/git/github/gist/get_tokens.py", line 22, in get_master_token
    res = perform_master_login(username, password, android_id)
  File "/home/artickl/.local/lib/python3.9/site-packages/gpsoauth/__init__.py", line 143, in perform_master_login
    return _perform_auth_request(data, proxy)
  File "/home/artickl/.local/lib/python3.9/site-packages/gpsoauth/__init__.py", line 78, in _perform_auth_request
    session.mount(AUTH_URL, AuthHTTPAdapter())
  File "/home/artickl/.local/lib/python3.9/site-packages/requests/adapters.py", line 155, in __init__
    self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
  File "/home/artickl/.local/lib/python3.9/site-packages/gpsoauth/__init__.py", line 68, in init_poolmanager
    context.set_ciphers(ssl_.DEFAULT_CIPHERS)
AttributeError: module 'urllib3.util.ssl_' has no attribute 'DEFAULT_CIPHERS'

@ProAdmin007
Copy link

Do not name your python file token.py this will create a circular import and the code wil not run!

@Korben85
Copy link

Korben85 commented Jun 6, 2023

I tried downgrading and running the script but
pip install urllib3\<=2
installs the version 2.0.0 which also results in this error
I used
pip install urllib3\<2
instead to install urllib3-1.26.16
The script finishes w/o an error now.
I still got no master token, but that's not the fault of the script, I think.
However, I hope this helps someone else.

@thoompje
Copy link

thoompje commented Jun 7, 2023

Hello All,

The tool won't extract any token, can someone please help! Would be really appreciated.

image

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