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"


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

f = open(file_name, "w")

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

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 ...

# 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(

# 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_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")

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

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


Hope this helps


Thank You

this code worked for several months but now not anymore

here is my python error

Traceback (most recent call last):
   File "refresh_token.py", line 70, in <module>
     owner_api_access_token = json.loads(owner_api_response.text)['access_token']
KeyError: 'access_token'


I am currently unable to check my installation as it is at a remote site currently experiencing an extended internet outage.

Are you still experiencing difficulties?

What is shown in your file?

Is your Tesla Access Token application still working?

yes my application is working.
but my script is not working.
my expiration date has gone one month ago



I run script: tesla_refresh.py every month as a cronjob.

But I’ve just run it in an SSH terminal. It ran OK and I now have a new authority token with a 45 day validity – all just as expected.

Firstly, I suggest that you try running the script again.

Do you have the following files in /home/pi/tesla-scripts? - access_token_expiry.txt, access_token.txt and sso_refresh_token.txt. The date/time on these files should be the date/time you last ran the script.

If it still does not work then I suggest you start over again from the beginning …

What version of the Mobile App Tesla Tokens do you have? The latest is 2.0.3 released in March as a result of a Tesla change, I understand.

Follow the steps described at the beginning of this forum to create the scripts: initiate_get_access_token.py and tesla_refresh.py. Then run tesla_refresh.py.

I recommend that it is set up to run monthly as a cronjob. This will avoid the access token validity expiring.
Good luck

Please post your findings in this forum thread as it may be helpful to other users.

thank you
I have the same problem

do you have an idea ?


I have no further ideas
I suggest you fully follow my suggestions in my previous post

hello, I have already tried everything from the beginning
the version my ios app is 1.0.7 but it’s up to date


My system is working - I use an Android App - Tesla Tokens

The difference between us seem to be that you use an Apple App

Is it possible for you to access an Android phone and try that App - it only has to be done once

non désolé, je n’ai pas de téléphone Android.
but before may it was working


When I Google - apple “tesla token” - several possiilities appear.
Why not try a different Apple App?

I’ve the same problem with the android app

My system is still working.
I’ve just tried the Android app - Tesla Tokens and it gave me a new token and an SSO Refresh token.
I’ve run out of ideas/things to suggest.
Sorry that I can’t help further

can you check if this is correction please ?
I’ve an 400 error

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(

Per Google …

The HyperText Transfer Protocol (HTTP) 400 Bad Request response status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (for example, malformed request syntax, invalid request message framing, or deceptive request routing).

From the code lines you have provided, it looks like you have incorrect indentations.

Please take a very careful look at those same lines in the code I provided in my original post to this thread back in Aug 21.

Hope this helps

the indentation is good, it was the copy paste that reindented it


You do not seem to be exactly following the method outlined in my original post.

And incidentally I don’t see the preceding line …
payload = {

I’m sorry but I don’t know how to help further