Step 1-4 + refresh_token in PHP #283
Replies: 9 comments 12 replies
-
Beta Was this translation helpful? Give feedback.
-
can't get this to work. Could you please provide a complete script ? I tried adding a class and adding base64url functions but I still get following notices and no result:
|
Beta Was this translation helpful? Give feedback.
-
ok thanks, that explains a lot :) But still an issue: so I tried :
but I get:
|
Beta Was this translation helpful? Give feedback.
-
I copy/pasted the whole lib in there. Must be forgetting something stupid ... <?php
class Tesla
{
protected $apiBaseUrl = "https://owner-api.teslamotors.com/api/1";
protected $tokenUrl = 'https://owner-api.teslamotors.com/oauth/token';
protected $tokenUrlNew = 'https://auth.tesla.com/oauth2/v3/token';
protected $accessUrl = 'https://auth.tesla.com/oauth2/v3/authorize';
protected $accessToken;
protected $vehicleId = null;
public function __construct(string $accessToken = null)
{
$this->accessToken = $accessToken;
}
public function setAccessToken(string $accessToken)
{
$this->accessToken = $accessToken;
}
public function allData()
{
return $this->sendRequest('/vehicle_data')['response'];
}
public function vehicles()
{
return $this->sendRequest('/vehicles');
}
public function vehicle()
{
return $this->sendRequest('')['response'];
}
public function setVehicleId(int $vehicleId)
{
$this->vehicleId = $vehicleId;
}
public function setClientId(string $clientId)
{
putenv('TESLA_CLIENT_ID=' . $clientId);
}
public function setClientSecret(string $clientSecret)
{
putenv('TESLA_CLIENT_SECRET=' . $clientSecret);
}
public function mobileEnabled()
{
return $this->sendRequest('/mobile_enabled')['response'];
}
public function chargeState()
{
return $this->sendRequest('/data_request/charge_state')['response'];
}
public function climateState()
{
return $this->sendRequest('/data_request/climate_state')['response'];
}
public function driveState()
{
return $this->sendRequest('/data_request/drive_state')['response'];
}
public function guiSettings()
{
return $this->sendRequest('/data_request/gui_settings')['response'];
}
public function vehicleState()
{
return $this->sendRequest('/data_request/vehicle_state')['response'];
}
public function vehicleConfig()
{
return $this->sendRequest('/data_request/vehicle_config')['response'];
}
public function wakeUp()
{
return $this->sendRequest('/wake_up', [], 'POST')['response'];
}
public function startSoftwareUpdate( int $seconds = 0 )
{
return $this->sendRequest('/command/schedule_software_update', [ 'offset_sec' => $seconds ], 'POST')['response'];
}
public function setValetMode(bool $active = false, int $pin = 0000)
{
$params = [
'on' => $active,
'pin' => $pin
];
return $this->sendRequest('/command/set_valet_mode', $params, 'POST')['response'];
}
public function resetValetPin()
{
return $this->sendRequest('/command/reset_valet_pin', [], 'POST')['response'];
}
public function openChargePort()
{
return $this->sendRequest('/command/charge_port_door_open', [], 'POST')['response'];
}
public function setChargeLimitToStandard()
{
return $this->sendRequest('/command/charge_standard', [], 'POST')['response'];
}
public function setChargeLimitToMaxRange()
{
return $this->sendRequest('/command/charge_max_range', [], 'POST')['response'];
}
public function setChargeLimit(int $percent = 90)
{
$params = [
'percent' => "$percent"
];
return $this->sendRequest('/command/set_charge_limit', $params, 'POST')['response'];
}
public function startCharging()
{
return $this->sendRequest('/command/charge_start', [], 'POST')['response'];
}
public function stopCharging()
{
return $this->sendRequest('/command/charge_stop', [], 'POST')['response'];
}
public function flashLights()
{
return $this->sendRequest('/command/flash_lights', [], 'POST')['response'];
}
public function honkHorn()
{
return $this->sendRequest('/command/honk_horn', [], 'POST')['response'];
}
public function unlockDoors()
{
return $this->sendRequest('/command/door_unlock', [], 'POST')['response'];
}
public function lockDoors()
{
return $this->sendRequest('/command/door_lock', [], 'POST')['response'];
}
public function windowControl(string $state = 'close', int $lat = 0, int $lon = 0)
{
return $this->sendRequest('/command/window_control', [ 'command' => $state, 'lat' => $lat, 'lon' => $lon ], 'POST')['response'];
}
public function setTemperature(float $driverDegreesCelcius = 20.0, float $passengerDegreesCelcius = 20.0)
{
return $this->sendRequest('/command/set_temps?driver_temp=' . $driverDegreesCelcius . '&passenger_temp=' . $passengerDegreesCelcius, [], 'POST')['response'];
}
public function startHvac()
{
return $this->sendRequest('/command/auto_conditioning_start', [], 'POST')['response'];
}
public function stopHvac()
{
return $this->sendRequest('/command/auto_conditioning_stop', [], 'POST')['response'];
}
public function movePanoramicRoof(string $state = 'vent', int $percent = 50)
{
return $this->sendRequest('/command/sun_roof_control?state=' . $state . '&percent=' . $percent, [], 'POST')['response'];
}
public function remoteStart(string $password = '')
{
return $this->sendRequest('/command/remote_start_drive?password=' . $password, [], 'POST')['response'];
}
public function openTrunk()
{
return $this->sendRequest('/command/actuate_trunk', [ 'which_trunk' => 'rear' ], 'POST')['response'];
}
public function openFrunk()
{
return $this->sendRequest('/command/actuate_trunk', [ 'which_trunk' => 'front' ], 'POST')['response'];
}
public function setNavigation(string $location)
{
$params = [
'type' => 'share_ext_content_raw',
'value' => [
'android.intent.extra.TEXT' => $location
],
'locale' => 'en-US',
'timestamp_ms' => time(),
];
return $this->sendRequest('/command/navigation_request', $params, 'POST')['response'];
}
public function startSentry()
{
return $this->sendRequest('/command/set_sentry_mode', [ 'on' => True], 'POST')['response'];
}
public function stopSentry()
{
return $this->sendRequest('/command/set_sentry_mode', [ 'on' => False], 'POST')['response'];
}
public function setSeatHeater(int $heater = 0, int $level = 0)
{
return $this->sendRequest('/command/remote_seat_heater_request', ['heater' => $heater, 'level' => $level], 'POST')['response'];
}
public function setTemps(float $driver = 21.0, float $passenger = 21.0)
{
return $this->sendRequest('/command/set_temps', ['driver_temp' => $driver, 'passenger_temp' => $passenger], 'POST')['response'];
}
public function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
public function getAccessToken(string $username, string $password)
{
###Step 1: Obtain the login page
$code_verifier = substr(hash('sha512', mt_rand()), 0, 86);
$state = $this->base64url_encode(substr(hash('sha256', mt_rand()), 0, 12));
$code_challenge = $this->base64url_encode($code_verifier);
$data =[
'client_id' => 'ownerapi',
'code_challenge' => $code_challenge,
'code_challenge_method' => 'S256',
'redirect_uri' => 'https://auth.tesla.com/void/callback',
'response_type' => 'code',
'scope' => 'openid email offline_access',
'state' => $state,
];
$GetUrl = $this->accessUrl.'?'.http_build_query ($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $GetUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HEADER, 1);
$apiResult = curl_exec($ch);
curl_close($ch);
$dom = new DomDocument();
@ $dom->loadHTML($apiResult);
$child_elements = $dom->getElementsByTagName('input'); //DOMNodeList
foreach( $child_elements as $h2 ) {
$hiddeninputs[$h2->getAttribute('name')]=$h2->getAttribute('value');
}
$headers = [];
$output = rtrim($apiResult);
$data = explode("\n",$output);
$headers['status'] = $data[0];
array_shift($data);
foreach($data as $part){
//some headers will contain ":" character (Location for example), and the part after ":" will be lost, Thanks to @Emanuele
$middle = explode(":",$part,2);
//Supress warning message if $middle[1] does not exist, Thanks to @crayons
if ( !isset($middle[1]) ) { $middle[1] = null; }
$headers[trim($middle[0])] = trim($middle[1]);
}
$cookie = $headers['Set-Cookie'];
###Step 2: Obtain an authorization code
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $GetUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded','Cookie: '.$cookie));
$postData = array(
'_csrf' => $hiddeninputs['_csrf'],
'_phase' => $hiddeninputs['_phase'],
'_process' => $hiddeninputs['_process'],
'transaction_id' => $hiddeninputs['transaction_id'],
'cancel' =>$hiddeninputs['cancel'],
'identity' => $username,
'credential' => $password
);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
$apiResult = curl_exec($ch);
curl_close($ch);
#print_r($apiResult);
$code= explode('&',explode('https://auth.tesla.com/void/callback?code=',$apiResult)[1])[0];
#print 'CODE'.$code;
###Step 3: Exchange authorization code for bearer token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrlNew);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
'X-Tesla-User-Agent: TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'authorization_code',
'client_id' => 'ownerapi',
'code' => $code,
'code_verifier' => $code_verifier,
'redirect_uri' => 'https://auth.tesla.com/void/callback'
]));
$apiResult = curl_exec($ch);
curl_close($ch);
$apiResultJson = json_decode($apiResult, true);
$BearerToken = $apiResultJson['access_token'];
$RefreshToken = $apiResultJson['refresh_token'];
###Step 4: Exchange bearer token for access token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer '.$BearerToken,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'client_id' => getenv('TESLA_CLIENT_ID'),
'client_secret' => getenv('TESLA_CLIENT_SECRET'),
]));
$apiResult = curl_exec($ch);
curl_close($ch);
$apiResultJson = json_decode($apiResult, true);
$apiResultJson['refresh_token']=$RefreshToken;
#print_r($apiResultJson);exit;
$this->accessToken = $apiResultJson['access_token'];
return $apiResultJson;
}
public function refreshAccessToken(string $refreshToken)
{
$tesla = new Tesla();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://pastebin.com/raw/pS7Z6yyP');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
$api = explode(PHP_EOL,$result);
$id=explode('=',$api[0]);
$secret=explode('=',$api[1]);
$tesla->setClientId(trim($id[1]));
$tesla->setClientSecret(trim($secret[1]));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrlNew);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
'X-Tesla-User-Agent: TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
]);
#print 'XX '.getenv('TESLA_CLIENT_ID');exit;
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'refresh_token',
'client_id' => 'ownerapi',
'client_secret' => getenv('TESLA_CLIENT_SECRET'),
'refresh_token' => $refreshToken,
'scope' => 'openid email offline_access'
]));
$apiResult = curl_exec($ch);
$apiResultJson = json_decode($apiResult, true);
curl_close($ch);
#print_r($apiResult);exit;
$apiResultJson = json_decode($apiResult, true);
$BearerToken = $apiResultJson['access_token'];
$RefreshToken = $apiResultJson['refresh_token'];
###Step 4: Exchange bearer token for access token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer '.$BearerToken,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'client_id' => getenv('TESLA_CLIENT_ID'),
'client_secret' => getenv('TESLA_CLIENT_SECRET'),
]));
$apiResult = curl_exec($ch);
curl_close($ch);
$apiResultJson = json_decode($apiResult, true);
$apiResultJson['refresh_token']=$RefreshToken;
#print_r($apiResultJson);exit;
$this->accessToken = $apiResultJson['access_token'];
return $apiResultJson;
}
protected function sendRequest(string $endpoint, array $params = [], string $method = 'GET')
{
$ch = curl_init();
if ($endpoint !== '/vehicles' && ! is_null($this->vehicleId)) {
$endpoint = '/vehicles/' . $this->vehicleId . $endpoint;
}
curl_setopt($ch, CURLOPT_URL, $this->apiBaseUrl . $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
'X-Tesla-User-Agent: TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
'Authorization: Bearer ' . $this->accessToken,
]);
if ($method == 'POST' || $method == 'PUT' || $method == 'DELETE') {
if ($method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
}
if (in_array($method, ['PUT', 'DELETE'])) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
}
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
}
$apiResult = curl_exec($ch);
$headerInfo = curl_getinfo($ch);
$apiResultJson = json_decode($apiResult, true);
curl_close($ch);
$result = [];
if ($apiResult === false) {
$result['errorcode'] = 0;
$result['errormessage'] = curl_error($ch);
//print $result['errormessage'].' api<br>';
}
if (! in_array($headerInfo['http_code'], ['200', '201', '204'])) {
$result['errorcode'] = $headerInfo['http_code'];
if (isset($apiResult)) {
$result['errormessage'] = $apiResult;
}
//print $result['errormessage'].' header<br>';;
}
return $apiResultJson ?? $apiResult;
}
}
$t = new Tesla;
var_dump($t->getAccessToken("login", "password"));
?> |
Beta Was this translation helpful? Give feedback.
-
Just FYI, I added code fences around all the example code in this thread. For future reference, you can use three backticks and the name of the language (```php) to set a multi-line block of code with syntax highlighting. Close it out with three more backticks at the end. |
Beta Was this translation helpful? Give feedback.
-
WORKING SCRIPT(As of this comment.) Here's a complete working script. (Fixed a case-sensitivity bug in the Just change your <?php
class Tesla
{
protected $apiBaseUrl = "https://owner-api.teslamotors.com/api/1";
protected $tokenUrl = 'https://owner-api.teslamotors.com/oauth/token';
protected $tokenUrlNew = 'https://auth.tesla.com/oauth2/v3/token';
protected $accessUrl = 'https://auth.tesla.com/oauth2/v3/authorize';
protected $accessToken;
protected $vehicleId = null;
public function __construct(string $accessToken = null)
{
$this->accessToken = $accessToken;
}
public function setAccessToken(string $accessToken)
{
$this->accessToken = $accessToken;
}
public function allData()
{
return $this->sendRequest('/vehicle_data')['response'];
}
public function vehicles()
{
return $this->sendRequest('/vehicles');
}
public function vehicle()
{
return $this->sendRequest('')['response'];
}
public function setVehicleId(int $vehicleId)
{
$this->vehicleId = $vehicleId;
}
public function setClientId(string $clientId)
{
putenv('TESLA_CLIENT_ID=' . $clientId);
}
public function setClientSecret(string $clientSecret)
{
putenv('TESLA_CLIENT_SECRET=' . $clientSecret);
}
public function mobileEnabled()
{
return $this->sendRequest('/mobile_enabled')['response'];
}
public function chargeState()
{
return $this->sendRequest('/data_request/charge_state')['response'];
}
public function climateState()
{
return $this->sendRequest('/data_request/climate_state')['response'];
}
public function driveState()
{
return $this->sendRequest('/data_request/drive_state')['response'];
}
public function guiSettings()
{
return $this->sendRequest('/data_request/gui_settings')['response'];
}
public function vehicleState()
{
return $this->sendRequest('/data_request/vehicle_state')['response'];
}
public function vehicleConfig()
{
return $this->sendRequest('/data_request/vehicle_config')['response'];
}
public function wakeUp()
{
return $this->sendRequest('/wake_up', [], 'POST')['response'];
}
public function startSoftwareUpdate( int $seconds = 0 )
{
return $this->sendRequest('/command/schedule_software_update', [ 'offset_sec' => $seconds ], 'POST')['response'];
}
public function setValetMode(bool $active = false, int $pin = 0000)
{
$params = [
'on' => $active,
'pin' => $pin
];
return $this->sendRequest('/command/set_valet_mode', $params, 'POST')['response'];
}
public function resetValetPin()
{
return $this->sendRequest('/command/reset_valet_pin', [], 'POST')['response'];
}
public function openChargePort()
{
return $this->sendRequest('/command/charge_port_door_open', [], 'POST')['response'];
}
public function setChargeLimitToStandard()
{
return $this->sendRequest('/command/charge_standard', [], 'POST')['response'];
}
public function setChargeLimitToMaxRange()
{
return $this->sendRequest('/command/charge_max_range', [], 'POST')['response'];
}
public function setChargeLimit(int $percent = 90)
{
$params = [
'percent' => "$percent"
];
return $this->sendRequest('/command/set_charge_limit', $params, 'POST')['response'];
}
public function startCharging()
{
return $this->sendRequest('/command/charge_start', [], 'POST')['response'];
}
public function stopCharging()
{
return $this->sendRequest('/command/charge_stop', [], 'POST')['response'];
}
public function flashLights()
{
return $this->sendRequest('/command/flash_lights', [], 'POST')['response'];
}
public function honkHorn()
{
return $this->sendRequest('/command/honk_horn', [], 'POST')['response'];
}
public function unlockDoors()
{
return $this->sendRequest('/command/door_unlock', [], 'POST')['response'];
}
public function lockDoors()
{
return $this->sendRequest('/command/door_lock', [], 'POST')['response'];
}
public function windowControl(string $state = 'close', int $lat = 0, int $lon = 0)
{
return $this->sendRequest('/command/window_control', [ 'command' => $state, 'lat' => $lat, 'lon' => $lon ], 'POST')['response'];
}
public function setTemperature(float $driverDegreesCelcius = 20.0, float $passengerDegreesCelcius = 20.0)
{
return $this->sendRequest('/command/set_temps?driver_temp=' . $driverDegreesCelcius . '&passenger_temp=' . $passengerDegreesCelcius, [], 'POST')['response'];
}
public function startHvac()
{
return $this->sendRequest('/command/auto_conditioning_start', [], 'POST')['response'];
}
public function stopHvac()
{
return $this->sendRequest('/command/auto_conditioning_stop', [], 'POST')['response'];
}
public function movePanoramicRoof(string $state = 'vent', int $percent = 50)
{
return $this->sendRequest('/command/sun_roof_control?state=' . $state . '&percent=' . $percent, [], 'POST')['response'];
}
public function remoteStart(string $password = '')
{
return $this->sendRequest('/command/remote_start_drive?password=' . $password, [], 'POST')['response'];
}
public function openTrunk()
{
return $this->sendRequest('/command/actuate_trunk', [ 'which_trunk' => 'rear' ], 'POST')['response'];
}
public function openFrunk()
{
return $this->sendRequest('/command/actuate_trunk', [ 'which_trunk' => 'front' ], 'POST')['response'];
}
public function setNavigation(string $location)
{
$params = [
'type' => 'share_ext_content_raw',
'value' => [
'android.intent.extra.TEXT' => $location
],
'locale' => 'en-US',
'timestamp_ms' => time(),
];
return $this->sendRequest('/command/navigation_request', $params, 'POST')['response'];
}
public function startSentry()
{
return $this->sendRequest('/command/set_sentry_mode', [ 'on' => True], 'POST')['response'];
}
public function stopSentry()
{
return $this->sendRequest('/command/set_sentry_mode', [ 'on' => False], 'POST')['response'];
}
public function setSeatHeater(int $heater = 0, int $level = 0)
{
return $this->sendRequest('/command/remote_seat_heater_request', ['heater' => $heater, 'level' => $level], 'POST')['response'];
}
public function setTemps(float $driver = 21.0, float $passenger = 21.0)
{
return $this->sendRequest('/command/set_temps', ['driver_temp' => $driver, 'passenger_temp' => $passenger], 'POST')['response'];
}
public function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
public function getAccessToken(string $username, string $password)
{
###Step 1: Obtain the login page
$code_verifier = substr(hash('sha512', mt_rand()), 0, 86);
$state = $this->base64url_encode(substr(hash('sha256', mt_rand()), 0, 12));
$code_challenge = $this->base64url_encode($code_verifier);
$data =[
'client_id' => 'ownerapi',
'code_challenge' => $code_challenge,
'code_challenge_method' => 'S256',
'redirect_uri' => 'https://auth.tesla.com/void/callback',
'response_type' => 'code',
'scope' => 'openid email offline_access',
'state' => $state,
];
$GetUrl = $this->accessUrl.'?'.http_build_query ($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $GetUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HEADER, 1);
$apiResult = curl_exec($ch);
curl_close($ch);
$dom = new DomDocument();
@ $dom->loadHTML($apiResult);
$child_elements = $dom->getElementsByTagName('input'); //DOMNodeList
foreach( $child_elements as $h2 ) {
$hiddeninputs[$h2->getAttribute('name')]=$h2->getAttribute('value');
}
$headers = [];
$output = rtrim($apiResult);
$data = explode("\n",$output);
$headers['status'] = $data[0];
array_shift($data);
foreach($data as $part){
//some headers will contain ":" character (Location for example), and the part after ":" will be lost, Thanks to @Emanuele
$middle = explode(":",$part,2);
//Supress warning message if $middle[1] does not exist, Thanks to @crayons
if ( !isset($middle[1]) ) { $middle[1] = null; }
$headers[trim($middle[0])] = trim($middle[1]);
}
$cookie = $headers['set-cookie'];
###Step 2: Obtain an authorization code
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $GetUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded','Cookie: '.$cookie));
$postData = array(
'_csrf' => $hiddeninputs['_csrf'],
'_phase' => $hiddeninputs['_phase'],
'_process' => $hiddeninputs['_process'],
'transaction_id' => $hiddeninputs['transaction_id'],
'cancel' =>$hiddeninputs['cancel'],
'identity' => $username,
'credential' => $password
);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
$apiResult = curl_exec($ch);
curl_close($ch);
#print_r($apiResult);
$code= explode('&',explode('https://auth.tesla.com/void/callback?code=',$apiResult)[1])[0];
#print 'CODE'.$code;
###Step 3: Exchange authorization code for bearer token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrlNew);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
'X-Tesla-User-Agent: TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'authorization_code',
'client_id' => 'ownerapi',
'code' => $code,
'code_verifier' => $code_verifier,
'redirect_uri' => 'https://auth.tesla.com/void/callback'
]));
$apiResult = curl_exec($ch);
curl_close($ch);
$apiResultJson = json_decode($apiResult, true);
$BearerToken = $apiResultJson['access_token'];
$RefreshToken = $apiResultJson['refresh_token'];
###Step 4: Exchange bearer token for access token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer '.$BearerToken,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'client_id' => getenv('TESLA_CLIENT_ID'),
'client_secret' => getenv('TESLA_CLIENT_SECRET'),
]));
$apiResult = curl_exec($ch);
curl_close($ch);
$apiResultJson = json_decode($apiResult, true);
$apiResultJson['refresh_token']=$RefreshToken;
#print_r($apiResultJson);exit;
$this->accessToken = $apiResultJson['access_token'];
return $apiResultJson;
}
public function refreshAccessToken(string $refreshToken)
{
$tesla = new Tesla();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://pastebin.com/raw/pS7Z6yyP');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
$api = explode(PHP_EOL,$result);
$id=explode('=',$api[0]);
$secret=explode('=',$api[1]);
$tesla->setClientId(trim($id[1]));
$tesla->setClientSecret(trim($secret[1]));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrlNew);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
'X-Tesla-User-Agent: TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
]);
#print 'XX '.getenv('TESLA_CLIENT_ID');exit;
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'refresh_token',
'client_id' => 'ownerapi',
'client_secret' => getenv('TESLA_CLIENT_SECRET'),
'refresh_token' => $refreshToken,
'scope' => 'openid email offline_access'
]));
$apiResult = curl_exec($ch);
$apiResultJson = json_decode($apiResult, true);
curl_close($ch);
#print_r($apiResult);exit;
$apiResultJson = json_decode($apiResult, true);
$BearerToken = $apiResultJson['access_token'];
$RefreshToken = $apiResultJson['refresh_token'];
###Step 4: Exchange bearer token for access token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->tokenUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer '.$BearerToken,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'client_id' => getenv('TESLA_CLIENT_ID'),
'client_secret' => getenv('TESLA_CLIENT_SECRET'),
]));
$apiResult = curl_exec($ch);
curl_close($ch);
$apiResultJson = json_decode($apiResult, true);
$apiResultJson['refresh_token']=$RefreshToken;
#print_r($apiResultJson);exit;
$this->accessToken = $apiResultJson['access_token'];
return $apiResultJson;
}
protected function sendRequest(string $endpoint, array $params = [], string $method = 'GET')
{
$ch = curl_init();
if ($endpoint !== '/vehicles' && ! is_null($this->vehicleId)) {
$endpoint = '/vehicles/' . $this->vehicleId . $endpoint;
}
curl_setopt($ch, CURLOPT_URL, $this->apiBaseUrl . $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: Mozilla/5.0 (Linux; Android 9.0.0; VS985 4G Build/LRX21Y; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36',
'X-Tesla-User-Agent: TeslaApp/3.4.4-350/fad4a582e/android/9.0.0',
'Authorization: Bearer ' . $this->accessToken,
]);
if ($method == 'POST' || $method == 'PUT' || $method == 'DELETE') {
if ($method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
}
if (in_array($method, ['PUT', 'DELETE'])) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
}
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
}
$apiResult = curl_exec($ch);
$headerInfo = curl_getinfo($ch);
$apiResultJson = json_decode($apiResult, true);
curl_close($ch);
$result = [];
if ($apiResult === false) {
$result['errorcode'] = 0;
$result['errormessage'] = curl_error($ch);
//print $result['errormessage'].' api<br>';
}
if (! in_array($headerInfo['http_code'], ['200', '201', '204'])) {
$result['errorcode'] = $headerInfo['http_code'];
if (isset($apiResult)) {
$result['errormessage'] = $apiResult;
}
//print $result['errormessage'].' header<br>';;
}
return $apiResultJson ?? $apiResult;
}
}
$t = new Tesla();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://pastebin.com/raw/pS7Z6yyP');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$api = explode(PHP_EOL,$result);
$id=explode('=',$api[0]);
$secret=explode('=',$api[1]);
$t->setClientId(trim($id[1]));
$t->setClientSecret(trim($secret[1]));
var_dump($t->getAccessToken("login", "password"));
?> |
Beta Was this translation helpful? Give feedback.
-
Struggling with this :( I have curl enabled, same error if i try it at CLI or via IIS
|
Beta Was this translation helpful? Give feedback.
-
not working anymore since a couple of days ...
|
Beta Was this translation helpful? Give feedback.
-
This discussion is forked here: #288 I fixed one problem with the above code, but now I'm getting HTTP 403 on step 3. Hopefully I'll have a fix by tomorrow. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Just my quick and dirty version - works so far
EDIT: snipppp Code snippp
The code in the next comment is better
Beta Was this translation helpful? Give feedback.
All reactions