BMW-i-Remote icon indicating copy to clipboard operation
BMW-i-Remote copied to clipboard

why not use bmw-connecteddrive servers ?

Open jollyjinx opened this issue 7 years ago • 31 comments

I might be stupid, but why does one need to go through the hassle to reverse engineer the apps ( android or ios ) for that APIKey ? To me it looks like connecting to the website bmw-connecteddrive.com and retrieving the same json data there is cleaner. All keys get generated on the go. Nothing fancy only a few nerds can use. Or are there advantages to using b2vapi.bmwgroup.com server ?

jollyjinx avatar Dec 24 '16 10:12 jollyjinx

i dont understand - where do you find an API key or JSON data on bmw-connecteddrive.com?

mnbf9rca avatar Jan 02 '17 16:01 mnbf9rca

(I don't have a BMW any more, so this is speculation.)

If you can make the calls via the website, then it should be possible to sniff what requests your browser is making and then use those requests directly.

See how I used this technique for the Renault Zoe API https://shkspr.mobi/blog/2016/10/reverse-engineering-the-renault-zoe-api/

edent avatar Jan 02 '17 17:01 edent

@edent sure - and i've been looking in to it too to try to overcome #20 - but i was wondering whether @jollyjinx has found some published web service or something?

mnbf9rca avatar Jan 02 '17 17:01 mnbf9rca

ConnectedDrive is also not available in all regions while the API does still work despite this. e.g. Canada

JPTN avatar Jan 04 '17 17:01 JPTN

Just adding to this:

  • For the old CD website I implemented this (= scrapping/extracting stuff from HTML).
  • For the new JSON-based one it would be possible too (of course). Although the authentication part is now more complex (seems to be OAuth2 based).

I find using the API much easier... YMMV of course. (Of course, extracting the keys drove me nearly mad but that's another story. :) )

SleeplessAnnoyedNerd avatar Jan 13 '17 16:01 SleeplessAnnoyedNerd

may I add a question here: going the CD web browser way is much easier for me because I cannot intercept my Android 6.0.1 Smartphone communication due to a CA install cert bug with Screen lock. From what I understood I need at least the Base64 coded API key / secret to get my token.

with F12 Tools I see the POST www.bmw-connecteddrive.de/gcdm/oauth/revoke with Header

Content-Type: application/x-www-form-urlencoded Accept: application/json Authorization: Basic xyz****....

there is no token to that Point of time I could detect.

it is followed by POST https://customer.bmwgroup.com/gcdm/oauth/authenticate with a referrer

is there a way to reuse These Information and go the b2vapi.bmwgroup.com server API way`?

rs38 avatar May 31 '17 09:05 rs38

I did something similar to your suggestion as the app now uses certificate pinning - see https://github.com/needlerp/homebridge-bmw-connected

gadget-man avatar Nov 19 '17 20:11 gadget-man

I've got a working first version of a new API instead of b2vapi.bmwgroup.com over at bimmer_connected #140. It is using https://customer.bmwgroup.com for inital login and https://myc-profile.bmwgroup.com for all API calls (like the BMW Connected Android app).The OAuth flow is quite complex though and I don't know if there is a chance to reduce the amount of code required. You can also find the code in this gist.

rikroe avatar Nov 24 '19 18:11 rikroe

@rikroe thank you for the link. since a few days I cannot get CD requests working via b2vapi.bmwgroup.com anymore. If you say the android app is already using the alternate way, then it is probably deprecated now. Usually the CD server had severe hickups in peak hours with 500 errors but since 10th December I only get err 403 when using a valid token with b2vapi.bmwgroup.com/webapi/v1/user/vehicles/{VIN}/status.

rs38 avatar Dec 12 '19 14:12 rs38

Thats really strange - I am still able to use the "old" b2vapi, but when testing for US cars it didn't work at all... Maybe BMW is reworking their APIs right now...

rikroe avatar Dec 12 '19 15:12 rikroe

I was not quite correct, I'm not able to get the token anymore via b2vapi.bmwgroup.com/gcdm/oauth/token/ -> error Der Remoteserver hat einen Fehler zurückgegeben: (403) Unzulässig. Did they change the key and/or secret? 403 does not sound so much like deprecated.

getting a token via https://customer.bmwgroup.com/gcdm/oauth/authenticate works fine, but that token leads to the error mentioned via b2vapi.bmwgroup.com/webapi/v1/user/vehicles/{VIN}/status

rs38 avatar Dec 14 '19 13:12 rs38

and right now the BMW servers are down again. just wanted to implement your python workflow in my c# solution... b2vapi.bmwgroup.com/gcdm/oauth/token/ -> connection refused Android app and browser are also not working.

this is very common for the BMW services unfortunately :(

rs38 avatar Dec 14 '19 15:12 rs38

Heloo 14.12.2019 before 16:00 +1:00(Prag) Mobile application KO, data from BMW server KO. 14.12.2019 23:00 +1:00(Prag) -> Mobile application Ok, data from BMW server KO. Tested Application sniff comminication: BMW app in login connect to: 76.223.31.44 13.69.65.22 40.68.210.104, ip ssh has CN:'*.azurewebsites.net 13.248.151.210

15.12.2019 - Application - KO login not posible app try connection to: 76.223.31.44 13.69.66.140 13.248.151.210

BMW propably migrate or new technology application to Microsof Azure Cloud. :-(

Wait for BMW functional and sniff connection.

######################################## 16.12.2019 API functional, application functional ######################################## 18.12.2019 8:00 - 10:00 (Prag) API + application not functional

Havrla

havrla avatar Dec 15 '19 15:12 havrla

.The OAuth flow is quite complex

@rikroe did you figure out which OAuth 2 flow BMW is following (100% ?) as a standard, so you we could use a OAuth2-Client-helper lib? Your gist example is working fine, but re-inventing the wheel with storing and refreshing tokens does not look very sexy... :)

rs38 avatar Jan 06 '20 14:01 rs38

did you figure out which OAuth 2 flow BMW is following (100% ?) as a standard, so you we could use a OAuth2-Client-helper lib?

Unfortunately, not all all. It's weird as it is a two-step OAuth approach that needs to use cookies in between... I'm almost back to what OP mentioned and asking myself if all of the apps' functionalities is also available using the browser.

Cannot test that for my car though - don't have fancy cameras, EV or stuff like that available.

rikroe avatar Jan 06 '20 21:01 rikroe

@rikroe your 2 step approach is 1:1 reverse engineered from the Android .apk? Indeed that 2nd step and cookies is real crap and I have no clue where and how to use the refresh token and which one. And exactly these authentication services where the likely reason for CD to fail so much in the last months. Did you already check all those home automation repos, how they react on the change at BMW?

And I am pretty sure, that right now there are some nice driving values missing in the web-version, e.g. the Rex-consumption in l/100km.

Of course it doen't make sense to have 2 different APIs for web and app client, but BMW is probably more or less quite old fashioned in IT and lacks of good devs.

rs38 avatar Jan 07 '20 09:01 rs38

Thats really strange - I am still able to use the "old" b2vapi, but when testing for US cars it didn't work at all... Maybe BMW is reworking their APIs right now...

BTW: is that still true, you can get a token via POST on https://b2vapi.bmwgroup.com/gcdm/oauth/token/ ? I get the 403 sind one month

rs38 avatar Jan 07 '20 16:01 rs38

Yes, https://b2vapi.bmwgroup.com/gcdm/oauth/token is still working for me (both in Postman and when using bimmer_connected. It's a german car/connected drive account.

Really unfortunate that not everything is available in the web API - what I've seen (only looking at basic vehicle status and how to send POIs) is soo much clearer and more thoughtfully designed.

To your original question, the login flow is based on the sniffed network traffic (they do certificate pinning in the apk so you need to disable that first). But other than the sniffed traffic no idea what they're doing there.

Also the first login seems to be more or less the same - I think you can replace b2vapi.bmwgroup.com/ with customer.bmwgroup.com/. And then it gets crazy...

rikroe avatar Jan 07 '20 21:01 rikroe

indeed, it works with the python bimmer_connected cli.py but not with my .NET implementation (which stopped working at 10.12.19)

For me the HTTPS Posts look the same and it's hard to get the the python traffic inspected by Fiddler...

(2 hours capturing and comparing in between) (....)

I really cannot believe what I finally found:

  • I always POSTed on {server}/gcdm/oauth/token/ with a tailing "/"; omiting this changes the error from 403 to 400
  • I escaped the POST body and sent scope=authenticate_user%20remote_services%20vehicle_data; sending unescaped body finally made it work again.
  • I also never sent the "Credentials" header.... (and still not necessary)

all this worked till 10.12. and I was concluding they stopped the API servers leaving only the nested OAuth2 hell for my automation. But I was wondering that not a single repo was complaining about broken API. So it was my own fault, but BMW has hardened or changed their servers.

rs38 avatar Jan 08 '20 16:01 rs38

and again there is trouble to get the token POST {server}/gcdm/oauth/token get's me Error 400...

rs38 avatar Feb 15 '20 23:02 rs38

Heloo. Mobile aplication android - functional. API in europe/Czech Republic KO.

New hack mobile aplication ? For new API protocol ? :-(

havrla avatar Feb 15 '20 23:02 havrla

Yeah, seems BMW changed something again and we need to MITM the full network traffic. Trying to get my hands on an old android device, as it seems this is much easier to be done on Android <= Nougat...

rikroe avatar Feb 16 '20 11:02 rikroe

@rikroe worth checking the latest issues here: https://github.com/bimmerconnected/bimmer_connected/pull/140

rs38 avatar Feb 16 '20 12:02 rs38

Thanks! A quick fix for the old API ist available at bimmerconnected/bimmer_connected#151.

rikroe avatar Feb 16 '20 14:02 rikroe

got to fix it with my .NET port also. many thanks especially to see https://customer.bmwgroup.com/gcdm/oauth/authenticate is working fine without that crazy session cookie workflow...

rs38 avatar Feb 16 '20 16:02 rs38

Heloo new server connected ok, trouble: socMax (max battery capacity) for BMW i3 not available

[root@CL-ITNK-BMW ~]# ./bmw/bmw.py
https://customer.bmwgroup.com/api/vehicle/navigation/v1/WBY1Z41000VXXXXX
<Response [404]>
[root@CL-ITNK-BMW ~]#

:-(((

havrla avatar Feb 17 '20 12:02 havrla

aaa socmax on old servers is OK

[root@CL-ITNK-BMW ~]# ./bmw/bmw.py https://b2vapi.bmwgroup.com/api/vehicle/navigation/v1/WBY1Z41000VXXXXXX <Response [200]> {'latitude': 52.020723, 'longitude': 14.989973, 'isoCountryCode': 'CZE', 'auxPowerRegular': 1.4, 'auxPowerEcoPro': 1.2, 'auxPowerEcoProPlus': 0.4, 'soc': 11.439000129699707, 'eco': '659,489,421,421,402,475,632,6d0,76f,8ac,9e9', 'norm': '698,4b6,4ac,4ac,41a,48f,632,6d0,76f,8ac,9e9', 'ecoEv': '659,489,421,421,402,475,632,6d0,76f,8ac,9e9', 'normEv': '698,4b6,4ac,4ac,41a,48f,632,6d0,76f,8ac,9e9', 'vehicleMass': '1400', 'driveTrain': 'bev_rex', 'pendingUpdate': False, 'vehicleTracking': True, 'socmax': 16.9, 'kaccReg': '2412000', 'kdecReg': '3240000', 'kaccEco': '2520000', 'kdecEco': '3240000', 'kup': '3132000', 'kdown': '3384000'} [root@CL-ITNK-BMW ~]#

havrla avatar Feb 17 '20 12:02 havrla

https://customer.bmwgroup.com/api/vehicle/navigation/v1/WBY1Z41000VXXXXX

I guess this URL wasn't an endpoint for car data REST calls. Only for authentication.

rs38 avatar Feb 17 '20 13:02 rs38

only authentization - NO

[root@CL-ITNK-BMW ~]# ./bmw/bmw.py https://customer.bmwgroup.com/webapi/v1/user/vehicles/WBY1Z41000VZXXXXX/status

{'vehicleStatus': {'vin': 'WBY1Z41000VZXXXXX', 'mileage': 66156, 'updateReason': 'VEHICLE_SHUTDOWN_SECURED', 'updateTime': '2020-02-17T08:27:36+0000', 'doorDriverFront': 'CLOSED', 'doorDriverRear': 'CLOSED', 'doorPassengerFront': 'CLOSED', 'doorPassengerRear': 'CLOSED', 'windowDriverFront': 'CLOSED', 'windowDriverRear': 'CLOSED', 'windowPassengerFront': 'CLOSED', 'windowPassengerRear': 'CLOSED', 'sunroof': 'CLOSED', 'trunk': 'CLOSED', 'rearWindow': 'INVALID', 'hood': 'CLOSED', 'doorLockState': 'SECURED', 'parkingLight': 'OFF', 'positionLight': 'OFF', 'remainingFuel': 4, 'remainingRangeElectric': 72, 'remainingRangeElectricMls': 44, 'remainingRangeFuel': 66, 'remainingRangeFuelMls': 41, 'maxRangeElectric': 107, 'maxRangeElectricMls': 66, 'maxFuel': 8, 'connectionStatus': 'DISCONNECTED', 'chargingStatus': 'INVALID', 'chargingLevelHv': 70, 'lastChargingEndReason': 'CHARGING_GOAL_REACHED', 'lastChargingEndResult': 'SUCCESS', 'position': {'lat': 51.540783, 'lon': 14.934473, 'heading': 263, 'status': 'OK'}, 'internalDataTimeUTC': '2020-02-17T08:27:36', 'singleImmediateCharging': False, 'chargingConnectionType': 'CONDUCTIVE', 'chargingInductivePositioning': 'NOT_POSITIONED', 'vehicleCountry': 'CZ', 'checkControlMessages': [], 'cbsData': [{'cbsType': 'BRAKE_FLUID', 'cbsState': 'OK', 'cbsDueDate': '2020-10', 'cbsDescription': 'Next change due at the latest by the stated date.'}, {'cbsType': 'VEHICLE_CHECK', 'cbsState': 'OK', 'cbsDueDate': '2021-05', 'cbsDescription': 'Next visual inspection due when the stated distance has been covered or by the stated date.'}, {'cbsType': 'VEHICLE_TUV', 'cbsState': 'OK', 'cbsDueDate': '2021-05', 'cbsDescription': 'Next statutory vehicle inspection due by the stated date.'}], 'DCS_CCH_Activation': 'NA', 'DCS_CCH_Ongoing': False}} [root@CL-ITNK-BMW ~]#

NEW URL is authentization and status car data respons

havrla avatar Feb 17 '20 14:02 havrla

Heloo :-( After 20.12.2020 16:00
[root@CL-ITNK-BMW ~]# ./bmw/bmw.py https://customer.bmwgroup.com/webapi/oauth/token <Response [401]> [root@CL-ITNK-BMW ~]#

havrla avatar Feb 21 '20 12:02 havrla

BASE_URL = 'customer.bmwgroup.com'
#BASE_URL = 'b2vapi.bmwgroup.com'

def getToken(BASE_URL, username, password, timeout=(20, 20)):
    try:
        headers = {
                "Content-Type": "application/x-www-form-urlencoded",
                "Content-Length": "124",
                "Connection": "Keep-Alive",
                "Host": BASE_URL,
                "Accept-Encoding": "gzip",
                "Authorization": "Basic blF2NkNxdHhKdVhXUDc0eGYzQ0p3VUVQOjF6REh4NnVuNGNEanli"
                                 "TEVOTjNreWZ1bVgya0VZaWdXUGNRcGR2RFJwSUJrN3JPSg==",
                "Credentials": "nQv6CqtxJuXWP74xf3CJwUEP:1zDHx6un4cDjybLENN3kyfumX2kEYigWPcQpdvDRpIBk7rOJ",
                "User-Agent": "okhttp/2.60"}

        data = {
            'client_id': 'dbf0a542-ebd1-4ff0-a9a7-55172fbfce35',
            'response_type': 'token',
            'redirect_uri': 'https://www.bmw-connecteddrive.com/app/static/external-dispatch.html',
            'scope': 'authenticate_user vehicle_data remote_services',
            'username': username,
            'password': password}

        data = urllib.parse.urlencode(data)#       url = 'https://' + BASE_URL + '/webapi/oauth/token'
#        url = 'https://' + BASE_URL + '/webapi/oauth/token'
        url = 'https://' + BASE_URL + '/gcdm/oauth/authenticate'
        #print (url)
        r = requests.post(url, data=data, headers=headers, allow_redirects=False)
        #print (r)
        if r.status_code == 302:
            logging.info('Access token acquired')
            response_json = dict(
                    urllib.parse.parse_qsl(urllib.parse.urlparse(r.headers['Location']).fragment)
                )
            #print(response_json)
            #print(response_json['access_token'])
            return response_json['access_token']
        else:
            raise ValueError('Unable to login')

    except Exception as msg:
        logging.error(msg)

havrla avatar Nov 22 '20 22:11 havrla