400 status code after Password change


#1

I have an iOS app that integreates with the Nest api. Upon changing password through the nest website, I get a 400 bad request when I try to update the heat/cool set point.
Request

URL - https://firebase-apiserver25-tah01-iad01.dapi.production.nest.com:9553/devices/thermostats/MY_THERMOSTAT
Method - PUT
Remote address - firebase-apiserver25-tah01-iad01.dapi.production.nest.com/54.85.117.74:9553

Response
Response code - 400 Bad Request
{
“error”: “Write Error”,

}

  1. However, the app can successfully get all the devices and the associated metadata after the password change.

Request

same URL
Method - GET
same remote address

Response
Response Code - 200 OK
{
“humidity”: 45,
“locale”: “en-US”,
“temperature_scale”: “C”,
“is_using_emergency_heat”: false,
“has_fan”: true,
“software_version”: “5.8-8”,
“has_leaf”: true,
“where_id”: “mnIV1Y0ifFuU1vDYkUiHYcWrvNbwSX_QO_8WOunI1OH0MAVWTs0KAQ”,
“device_id”: “CTJJHPXFThNsujAcSbaL2wEzSB31qOGK”,
“name”: “A Nest Room”,
“can_heat”: true,
“can_cool”: true,
“target_temperature_c”: 16.5,
“target_temperature_f”: 62,
“target_temperature_high_c”: 32.0,
“target_temperature_high_f”: 90,
“target_temperature_low_c”: 15.5,
“target_temperature_low_f”: 60,
“ambient_temperature_c”: 25.0,
“ambient_temperature_f”: 77,
“away_temperature_high_c”: 28.5,
“away_temperature_high_f”: 84,
“away_temperature_low_c”: 12.0,
“away_temperature_low_f”: 54,
“eco_temperature_high_c”: 28.5,
“eco_temperature_high_f”: 84,
“eco_temperature_low_c”: 12.0,
“eco_temperature_low_f”: 54,
“is_locked”: false,
“locked_temp_min_c”: 20.0,
“locked_temp_min_f”: 68,
“locked_temp_max_c”: 22.0,
“locked_temp_max_f”: 72,
“sunlight_correction_active”: false,
“sunlight_correction_enabled”: true,
“structure_id”: “UNPW7JUxmjxpbRNLkUyDCKC-lRjFT_RwdtrMjv2ohYCZJdBF_NsIRA”,
“fan_timer_active”: false,
“fan_timer_timeout”: “1970-01-01T00:00:00.000Z”,
“fan_timer_duration”: 45,
“previous_hvac_mode”: “”,
“hvac_mode”: “heat”,
“time_to_target”: “~0”,
“time_to_target_training”: “ready”,
“where_name”: “A Nest Room”,
“label”: “”,
“name_long”: “A Nest Room Thermostat”,
“is_online”: true,
“last_connection”: “2018-06-01T13:20:13.524Z”,
“hvac_state”: “off”
}
3. Also after changing the password, if I update the heat/cool set point to a value that’s anything other than the one that the thermostat was set at before changing the password, I get a 400. But if I set the temperature the same as what it was before I changed the password I get a 200. For eg. If the thermostat was at 16.5 degrees. Then I change my password and update the thermostat to 17, I get a 400 write error. But if I change it back to 16.5 I get a 200ok.

Request

same URL
Method - PUT
same remote address
Contents -
{
“target_temperature_c”: 17
}

Response
Response code - 400 Bad Request
{
“error”: “Write Error”,

}

But setting it back to 16.5 I get a 200 ok

Response

{
“target_temperature_c”: 16.5
}

User shouldn’t be allowed to perform any activity after password change. As per API documentation we should be getting a 401 response code for invalid credentials. The nest app is consistent with the api documentation in the sense it returns a 401 upon changing the password. But this is not the case for the API. Will this be fixed to return 401?


#2

API access is driven by the OAuth access token. The user password drives the user’s access to their Nest account. They are two separate things, so changing the user password shouldn’t affect the API access given to a 3rd party integration.

If you are using the API endpoint of https://developer-api.nest.com you shouldn’t have any issues. The ones you are showing are redirect endpoints which shouldn’t be called directly, you should call https://developer-api.nest.com and handle redirects in your app as needed.

I’m pretty sure any error message about invalid credentials refers to the access token.


#3

@jbumgardner I am using the https://developer-api.nest.com/ API endpoint itself. The URL that I mentioned shows up when I intercept network traffic while sending the request but my code has the correct API endpoint. I’m surprised why I don’t receive a 401 for invalid credentials at least.


#4

How exactly are you making the call to developer-api.nest.com? Can you post the code?


#5

The initial request is sent to https://developer-api.nest.com/ but after getting the redirect url successfully, we use that in subsequent requests. As per the nest docs saving the redirect url since it stays the same for the given user.
https://developers.nest.com/documentation/cloud/how-to-handle-redirects#store_the_redirected_location

But I also tried sending all my requests to the right API endpoint instead of the redirect one, but I was still getting a 400 status code after password change instead of 401.


#6

Can you post the code of your API calls, including how you handle redirects? I can’t help unless I see what you’re doing.

Do you have the right permissions selected? Did you try reauthorizing the connection?

Changing the nest.com password for an account should have no effect on an integration’s access to that account via the API.


#7
  1. This is the code for making the call to the API endpoint -
NSURL *url = [NSURL URLWithString:nestCommand.getCommandURL relativeToURL:[NSURL URLWithString:NEST_API_URL]];
         if (redirectUrl) {
             url = [NSURL URLWithString:nestCommand.getCommandURL relativeToURL:[NSURL URLWithString:redirectUrl]];
         }
         NSMutableURLRequest *mutableRequest = [NSMutableURLRequest requestWithURL:url];
         [mutableRequest setValue:[@"Bearer " stringByAppendingString:accessToken] forHTTPHeaderField:@"Authorization"];
         mutableRequest.HTTPMethod = nestCommand.HTTPMethod;
         [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
         
          mutableRequest.timeoutInterval = TIMEOUT_INTERVAL;
          
        // if this is POST/PUT/PATCH there is a body
          if(![nestCommand.HTTPMethod isEqual:HTTPMETHOD_GET]) { 
 //set the body here
}

[[nsUrlSession dataTaskWithRequest:mutableRequest completionHandler:^
  (NSData *data, NSURLResponse *response, NSError *error) {
//handle response if it isn't a redirect
}
  1. This is the code that handles the redirects

    - (void)URLSession:(NSURLSession *)session
    
                  task:(NSURLSessionTask *)task
    willPerformHTTPRedirection:(NSHTTPURLResponse *)response
            newRequest:(NSURLRequest *)request
     completionHandler:(void (^)(NSURLRequest *))completionHandler {
        
        DDLogDebug(@"redirect response - %@ \n redirect request - %@", task.currentRequest.allHTTPHeaderFields, request.allHTTPHeaderFields);
        
        redirectUrl = [request.URL absoluteString];
        
        NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:request.URL];
        
        newRequest.HTTPMethod = task.currentRequest.HTTPMethod;
        newRequest.allHTTPHeaderFields = task.currentRequest.allHTTPHeaderFields;
        newRequest.HTTPBody = task.originalRequest.HTTPBody;
        
        DDLogDebug(@"currentRequest.HTTPMethod - %@, originalRequest.HTTPMethod - %@", task.currentRequest.HTTPMethod, task.originalRequest.HTTPMethod);
        DDLogDebug(@"currentRequest.allHTTPHeaderFields - %@, originalRequest.allHTTPHeaderFields - %@", task.currentRequest.allHTTPHeaderFields, task.originalRequest.allHTTPHeaderFields);
        DDLogDebug(@"currentRequest.HTTPBody - %@, originalRequest.HTTPBody - %@", task.currentRequest.HTTPBody, task.originalRequest.HTTPBody);
        
        completionHandler(newRequest);
    }
    

For reference this is the NEST_API_URL : https://developer-api.nest.com and getCommandURL gives something like - /devices/thermostats/deviceID

The redirect URL is “https://firebase-apiserver…”


#8

So does your call work if you do it a different way? Try it with a simple curl call on the command line.