Community
OpenEnergyMonitor

OpenEnergyMonitor Community

Tesla Access Tokens – Update

In early August, my Tesla Access Token failed to automatically update and so days later it expired. This then stopped Inputs to emoncms from the Tesla EV – soc, battery range miles and odometer reading.
And the reason? In July, Tesla had changed things – increasing security incl adding Captcha.

With a great deal of help from others, I now have a working solution which is in two parts.

Part 1 which is described in the Python script below involves a free Android App to copy and save the data. And it is possible just to use Part 1 every 30 or so days.

I do not have an iPhone but this looks like the Apple equivalent App:

# Script name:  initiate_get_access_token.py

# Introduction ...
# In July 2021, Tesla increased security re Access Tokens incl introduction of Captcha in the request
# This script is the first part of a work around
# It requires access to an Android mobile phone

# BEFORE YOU RUN THIS SCRIPT - Do Steps 1 to 3 below ...

# STEP 1 ...
# Install the Android App: Tesla Tokens
# Run the App and copy the SSO Refresh Token to the Clipboard
# Open gMail, paste the Clipboard as the message content and send it to yourself

# STEP 2 ...
# If the directory does not exist, do:  mkdir /home/pi/tesla-scripts

# STEP 3 ...
# Paste the SSO Refresh Token into the line as shown below ...
sso_refresh_token = "Paste the SSO Refresh Token between these double quotes"


# NOW RUN THE SCRIPT ...

file_name = "/home/pi/tesla-scripts/sso_refresh_token.txt"   # This file is read by other scripts ...

f = open(file_name, "w")
f.write(sso_refresh_token)
f.close()

"""
# For debugging only ...
# Open and read the file after the appending:
f = open(file_name, "r")
print(f.read()) 
f.close()
"""

print ("That's it!  A lot of hassle but you only have to do it once")
print ("Now proceed to the final step which is to run the script:  tesla_refresh.py")

Part 2 which is described in the Python script below, saves the key data to files – Access Token, Expiry Date and SSO Refresh Token. The script can then be set to run monthly in the background using Cron – until Tesla makes the next change, that is :frowning_face:

# Script Name:  tesla_refresh.py

# Introduction ...
# In July 2021, Tesla increased security re Access Tokens incl introduction of Captcha in the request
# This script is the second part of a work around process
# If the script is run every month as a cronjob, the Owner API Access Token will be refreshed before its 45 day expiry
# The valid Access Token is saved to file: /home/pi/tesla-scripts/access_token.txt and so can be accessed by other scripts

# Save script to:  /home/pi/tesla-scripts
# Run script using: python3 /home/pi/tesla-scripts/tesla_refresh.py
# Thereafter run the script every month as a cronjob

# Due acknowledgement to Tim Dorr Ref: https://tesla-api.timdorr.com/api-basics/authentication#refreshing-an-access-token
# Due acknowledgement to themonomers Ref: https://github.com/themonomers/tesla/blob/master/python/TeslaRefreshToken.py
# And thanks to Antoine Leveugle (@denouche)

import requests
import json
import urllib
import datetime
import pathlib
import shutil

# Read existing SSO Refresh_Token from the file created by script:  initiate_get_access_token.py
file_name = "/home/pi/tesla-scripts/sso_refresh_token.txt"
f = open(file_name, "r")
refresh_token = f.read()
# print (refresh_token)     # Debugging only ...
f.close()

                                       
# Exchange bearer token for access token
url = 'https://auth.tesla.com/oauth2/v3/token'
payload = {
  'grant_type': 'refresh_token',
  'refresh_token': refresh_token,
  'client_id': 'ownerapi',
  'scope': 'openid email offline_access'
}

response = requests.post(
             url,
             json=payload
           )


# Get new sso refresh token
new_sso_refresh_token = json.loads(response.text)['refresh_token']


# Get new owner api access token from sso access token
sso_access_token = json.loads(response.text)['access_token']

owner_api_url = 'https://owner-api.teslamotors.com/oauth/token'
owner_api_payload = {
  'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
  'client_id': '81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384'
}

owner_api_headers = {
  'Authorization': 'Bearer ' + sso_access_token
}

owner_api_response = requests.post(
             owner_api_url,
             json=owner_api_payload,
             headers=owner_api_headers
           )

owner_api_access_token = json.loads(owner_api_response.text)['access_token']


# Get expiry date for new owner api access token
expiry = str(datetime.datetime.fromtimestamp(json.loads(owner_api_response.text)['created_at'] + json.loads(owner_api_response.text)['expires_in']))


# Print KEY DATA for debugging ...
"""
print (" ")
print ('Owner API access_token: ' + owner_api_access_token)


print ('Expires at: ' + expiry)

print (" ")
print ('New SSO refresh_token: ' + new_sso_refresh_token)
"""

# Write KEY DATA to files ...

file_name = "/home/pi/tesla-scripts/access_token.txt"   # This file is read by other scripts ...
f = open(file_name, "w")
f.write(owner_api_access_token)
f.close()

file_name = "/home/pi/tesla-scripts/access_token_expiry.txt" 
f = open(file_name, "w")
f.write(expiry)
f.close()

file_name = "/home/pi/tesla-scripts/sso_refresh_token.txt"   
f = open(file_name, "w")
f.write(new_sso_refresh_token)
f.close()

# AFTER RUNNING THE SCRIPT - SET IT UP TO RUN MONTHLY USING CRON

Hope this helps

1 Like