MattTW / BlinkMonitorProtocol

Unofficial documentation for the Blink Wire-Free HD Home Monitoring & Alert System
412 stars 77 forks source link

token auth #57

Closed larxxor closed 2 years ago

larxxor commented 3 years ago

Hi, I'm trying to write the api in Java.

I can login and verify pin. When I try to load homescreen, I get {"message":"Unauthorized Access","code":101} I can parse out token. It is probably the token, I send wrong.

In the readme's the curl examples it says --header 'token-auth: xxxx But in the python files it is TOKEN_AUTH.

I am confused here. Does curl and/or python convert that to some header. That looks like two different header names to me.

greggolang commented 3 years ago

I'm having the same issue using golang. I'm able to auth but nothing after that. I get the same code when trying to get to the homescreen. BTW, this was working for me before. It has stopped working.

larxxor commented 3 years ago

Maybe we should investigate if the python scripts that float around still works. Or if there is an API change that caused it.

larxxor commented 3 years ago

The python script uses v4 login. And v5 login returns a completely different json structure.

In v4 the token is at "authtoken"."authtoken". In v5 it is placed in "account"."auth"."token"

I suspect the way token is passed in subsequent api calls has changed too...

greggolang commented 3 years ago

Any update on this issue?

larxxor commented 3 years ago

Yes, have a look at this issue : https://github.com/MattTW/BlinkMonitorProtocol/issues/49

Concerning the use of reauth in login payload, as well as other headers. In particular the code at the end. When I have time, I'm going to rewrite my code with that as inspiration, and see if it fixes things.

greggolang commented 3 years ago

Yes, have a look at this issue : #49

Concerning the use of reauth in login payload, as well as other headers. In particular the code at the end. When I have time, I'm going to rewrite my code with that as inspiration, and see if it fixes things.

I'm new to programming. Can you explain more what I need to do? I had this working until the change. THANKS!

larxxor commented 3 years ago

I have now homescreen working (and probably other calls will work too). When I get some time, I will detail the steps here.

greggolang commented 3 years ago

I have now homescreen working (and probably other calls will work too). When I get some time, I will detail the steps here.

GREAT! Thanks

greggolang commented 3 years ago

I have now homescreen working (and probably other calls will work too). When I get some time, I will detail the steps here.

Hi larxxor, I still haven't been able to find a way to make this work. I hope you can give some details. Thanks!

larxxor commented 3 years ago

Login code (Java)

`
String json = "{\"app_version\":\"6.1.6 (9289) #8fee5f53c-mod\", \"password\":\""+passwd+"\", \"reauth\":\"true\", \"os_version\":\"14.4\", \"device_identifier\":\"iPhone11,8\", \"unique_id\": \""+unique_id+"\",\"client_type\":\"ios\", \"email\":\""+email+"\", \"client_name\":\"iPhone xxx\"}";

    // add json header
    HttpRequest request = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .uri(URI.create(loginTier+post_login))
            .setHeader("User-Agent", "Java_HttpClient") // add request header
            .header("Content-Type", "application/json")
            .header("APP-BUILD", "IOS_9289")
            .build();

    // get response
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); `

post_login = /api/v5/account/login Extract token + clientId + accountid + tier from response. Token is a new one every login, the others does not seem to change. Email + password are your credentials. UUID can be created with an online uuid generator, needs to be the same always. Login tier is https://rest-prod.immedia-semi.com All the client info mimicing an iphone is maybe not needed.

First time a pin is sent to you, it needs to be verified

Verify code (java)

`
String json = "{\"pin\":\""+pin+"\", \"app_version\":\"6.1.6 (9289) #8fee5f53c-mod\", \"reauth\":\"true\", \"os_version\":\"14.4\", \"device_identifier\":\"iPhone11,8\", \"unique_id\": \""+unique_id+"\",\"client_type\":\"ios\", \"client_name\":\"iPhone xxx\"}";

    // add json header
    HttpRequest request = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .uri(URI.create(europeTier+"/api/v4/account/"+accountId+"/client/"+clientId+"/pin/verify"))
            .setHeader("User-Agent", "Java_HttpClient") // add request header
            .header("Content-Type", "application/json")
            .header("APP-BUILD", "IOS_9289")
            .header("TOKEN_AUTH", this.authToken)
            .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());`

Clientid + accountId from login response, I am on tier prde, so europeTier = https://rest-prde.immedia-semi.com authToken from login response. pin I receive over sms.

Now I can retrieve homescreen.

Homescreen code (java)

`
HttpRequest request = HttpRequest.newBuilder() .GET() .uri(URI.create(europeTier+"/api/v3/accounts/"+accountId+"/homescreen")) .setHeader("User-Agent", "Java_HttpClient") // add request header .header("Content-Type", "application/json") .header("APP-BUILD", "IOS_9289") .header("TOKEN_AUTH", this.authToken) .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

`

europeTies as in verify, authToken from login

greggolang commented 3 years ago

Login code (Java)

` String json = "{"app_version":"6.1.6 (9289) #8fee5f53c-mod", "password":""+passwd+"", "reauth":"true", "os_version":"14.4", "device_identifier":"iPhone11,8", "unique_id": ""+unique_id+"","client_type":"ios", "email":""+email+"", "client_name":"iPhone xxx"}";

    // add json header
    HttpRequest request = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .uri(URI.create(loginTier+post_login))
            .setHeader("User-Agent", "Java_HttpClient") // add request header
            .header("Content-Type", "application/json")
            .header("APP-BUILD", "IOS_9289")
            .build();

    // get response
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); `

post_login = /api/v5/account/login Extract token + clientId + accountid + tier from response. Token is a new one every login, the others does not seem to change. Email + password are your credentials. UUID can be created with an online uuid generator, needs to be the same always. Login tier is https://rest-prod.immedia-semi.com All the client info mimicing an iphone is maybe not needed.

First time a pin is sent to you, it needs to be verified

Verify code (java)

` String json = "{"pin":""+pin+"", "app_version":"6.1.6 (9289) #8fee5f53c-mod", "reauth":"true", "os_version":"14.4", "device_identifier":"iPhone11,8", "unique_id": ""+unique_id+"","client_type":"ios", "client_name":"iPhone xxx"}";

    // add json header
    HttpRequest request = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .uri(URI.create(europeTier+"/api/v4/account/"+accountId+"/client/"+clientId+"/pin/verify"))
            .setHeader("User-Agent", "Java_HttpClient") // add request header
            .header("Content-Type", "application/json")
            .header("APP-BUILD", "IOS_9289")
            .header("TOKEN_AUTH", this.authToken)
            .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());`

Clientid + accountId from login response, I am on tier prde, so europeTier = https://rest-prde.immedia-semi.com authToken from login response. pin I receive over sms.

Now I can retrieve homescreen.

Homescreen code (java)

` HttpRequest request = HttpRequest.newBuilder() .GET() .uri(URI.create(europeTier+"/api/v3/accounts/"+accountId+"/homescreen")) .setHeader("User-Agent", "Java_HttpClient") // add request header .header("Content-Type", "application/json") .header("APP-BUILD", "IOS_9289") .header("TOKEN_AUTH", this.authToken) .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

`

europeTies as in verify, authToken from login

This worked. Thanks!!!!

greggolang commented 3 years ago

Login code (Java)

` String json = "{"app_version":"6.1.6 (9289) #8fee5f53c-mod", "password":""+passwd+"", "reauth":"true", "os_version":"14.4", "device_identifier":"iPhone11,8", "unique_id": ""+unique_id+"","client_type":"ios", "email":""+email+"", "client_name":"iPhone xxx"}";

    // add json header
    HttpRequest request = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .uri(URI.create(loginTier+post_login))
            .setHeader("User-Agent", "Java_HttpClient") // add request header
            .header("Content-Type", "application/json")
            .header("APP-BUILD", "IOS_9289")
            .build();

    // get response
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); `

post_login = /api/v5/account/login Extract token + clientId + accountid + tier from response. Token is a new one every login, the others does not seem to change. Email + password are your credentials. UUID can be created with an online uuid generator, needs to be the same always. Login tier is https://rest-prod.immedia-semi.com All the client info mimicing an iphone is maybe not needed.

First time a pin is sent to you, it needs to be verified

Verify code (java)

` String json = "{"pin":""+pin+"", "app_version":"6.1.6 (9289) #8fee5f53c-mod", "reauth":"true", "os_version":"14.4", "device_identifier":"iPhone11,8", "unique_id": ""+unique_id+"","client_type":"ios", "client_name":"iPhone xxx"}";

    // add json header
    HttpRequest request = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .uri(URI.create(europeTier+"/api/v4/account/"+accountId+"/client/"+clientId+"/pin/verify"))
            .setHeader("User-Agent", "Java_HttpClient") // add request header
            .header("Content-Type", "application/json")
            .header("APP-BUILD", "IOS_9289")
            .header("TOKEN_AUTH", this.authToken)
            .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());`

Clientid + accountId from login response, I am on tier prde, so europeTier = https://rest-prde.immedia-semi.com authToken from login response. pin I receive over sms.

Now I can retrieve homescreen.

Homescreen code (java)

` HttpRequest request = HttpRequest.newBuilder() .GET() .uri(URI.create(europeTier+"/api/v3/accounts/"+accountId+"/homescreen")) .setHeader("User-Agent", "Java_HttpClient") // add request header .header("Content-Type", "application/json") .header("APP-BUILD", "IOS_9289") .header("TOKEN_AUTH", this.authToken) .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

`

europeTies as in verify, authToken from login

larxxor,

One more question. I've got the homescreen working Thank you. The problem that I'm having now is that the pin needs to be verified more than once. I'm using this as the unique_id : "00000000-0000-0000-0000-100000000001". Should I need to re verify the pin?

larxxor commented 3 years ago

I generate an UUID here (version 1) https://www.uuidgenerator.net/

This is reverse engineering, I don't know anything for sure. The idea is that UUID is unique for each client. And you carry that on from login to login.

I have tried changing the uuid and not been asked to verify pin. Which is very confusing. I am not sure at all how Blink is recognizing the client. I feel that if you test too much, with several requests right after another, it will trigger a breaker and stop working. My approach is to think and code very deliberately. Then go away and test it later.

greggolang commented 3 years ago

I generate an UUID here (version 1) https://www.uuidgenerator.net/

This is reverse engineering, I don't know anything for sure. The idea is that UUID is unique for each client. And you carry that on from login to login.

I have tried changing the uuid and not been asked to verify pin. Which is very confusing. I am not sure at all how Blink is recognizing the client. I feel that if you test too much, with several requests right after another, it will trigger a breaker and stop working. My approach is to think and code very deliberately. Then go away and test it later.

I've haven't been able to get this working. I am changing the UUID and the pin keeps coming. Any news from your side?

larxxor commented 3 years ago

Once you have an UUID you should stick to that and not change it. I think user-agent is important as well. Pay attention to the tier part, where login goes to one host, a pin arrives, amd then you perform a verify on the tier you got from login response.

Maybe share your code (minus email and password of course)

I have it working now yes, my alarm system is coded to trigger arm/disarm on blink. Works nicely again.

arnaduga commented 3 years ago

I got some issue to verify PIN.

I used POSTMAN for the moment.

Login is fine, retrieved my AccountID, ClientID, Token, I generated a UUID (and fixed it).

In the example sent by @larxxor, it is mentioned TOKEN_AUTH (with an underscore) where the doc mentions TOKEN-AUTH (with a dash).

I tried both and upercase/lowercase as well. But I always have a http/401:

{
    "message": "Unauthorized Access",
    "code": 101
}

Any clue?

The call done is:

curl --location --request POST 'https://rest-prod.immedia-semi.com/api/v4/account/12345/client/123456/pin/verify' \
--header 'token_auth: -1Hahsgdtmdxw_2ssldARZ' \
--header 'Content-Type: application/json' \
--data-raw '{
    "pin": "541979"
}'
larxxor commented 3 years ago

You've got wrong host on verify. It is not same host as login. Replace "prod" with tier from login response.

arnaduga commented 3 years ago

Damn, it was that...

Sorry, I did not get this tier value, but this makes senses... Login is "global", but then, it is regiolanized.

Works now!

Thank you

larxxor commented 3 years ago

Regarding TOKEN_AUTH vs TOKEN-AUTH vs token-auth. I have come to the conclusion that they are interchangeable.

I used TOKEN_AUTH because I found a code sample with that variety. Wonder if casing will be restricted in the future some day.

arnaduga commented 3 years ago

Ok. Let's hope it will be stable or at least not changed too often 🙂

Thanks

greggolang commented 3 years ago

Regarding TOKEN_AUTH vs TOKEN-AUTH vs token-auth. I have come to the conclusion that they are interchangeable.

I used TOKEN_AUTH because I found a code sample with that variety. Wonder if casing will be restricted in the future some day.

I've got it working again with the new UUID code. Thanks larxxor

sim2511 commented 11 months ago

Hello,

I'm also having the 101 code error , what am I doing wrong ? My tier is "e004" so i tried to put this is the first url also but same issue

username = username_entry.get()
password = password_entry.get()
url = "https://rest-prod.immedia-semi.com/api/v5/account/login"

# PrĂ©parez les donnĂ©es Ă  envoyer avec la requĂȘte
data = {
    "email": username,
    "password": password
}

# Envoyez la requĂȘte Ă  l'API de Blink
response = requests.post(url, json=data)

# Vérifiez si la connexion a réussi
if response.status_code == 200:
    # Si la connexion a réussi, extraire le token d'authentification et le client_id
    auth_token = response.json().get("auth").get("token")
    client_id = response.json().get("account").get("client_id")
    account_id = response.json().get("account").get("account_id")
    region = response.json().get("account").get("region")
    tier= response.json().get("account").get("tier")
    print(response.json())
    print("region :", region)
    print("account_id ", account_id)
    print("Auth token: ", auth_token)
    print("Client id: ", client_id)

else:
    print("Failed to log in:", response.content)

try:
    url_homescreen=f"https://rest-{tier}.immedia-semi.com/api/v3/accounts/{account_id}/homescreen"
    headers = {"token-auth": auth_token}
    response_homescreen = requests.get(url_homescreen, headers=headers)
    print(response_homescreen.json())
except Exception as e:
    print(f"Erreur lors de l'authentification : {e}")

The code I received from response..json(): {'account': {'account_id': X user_id': X client_id': ** client_trusted': False new_account': True tier': 'e004' region': 'eu' account_verification_required': False phone_verification_required': False client_verification_required': True require_trust_client_device': True country_required': False verification_channel': 'phone' user': {'user_id': X country': 'FR'} amazon_account_linked': True braze_external_id': 'X'} auth': {'token': '***'} phone': {'number': '**' last_4_digits': '**' country_calling_code': '' valid': True} verification': {'email': {'required': False} phone': {'required': True channel': 'sms'}} lockout_time_remaining': 0 force_password_reset': False allow_pin_resend_seconds': 90}

larxxor commented 11 months ago

There is a special sequence to acquire token on first login from device. This looks like you just do a user/passwd login. Wont work.

larxxor commented 11 months ago

I have a working solution, but in java.

host to be used for login : https://rest-prod.immedia-semi.com for all other requests use region tier url, for me that is https://rest-prde.immedia-semi.com

the data section in login should contain fields : String json = "{\"app_version\":\""+appVersion+"\", \"password\":\""+passwd+"\", \"reauth\":\"true\", \"os_version\":\""+osVersion+"\", \"device_identifier\":\""+deviceIdentifier+"\", \"unique_id\": \""+unique_id+"\",\"client_type\":\""+clientOs+"\", \"email\":\""+email+"\", \"client_name\":\""+clientName+"\"}";

Here are my values for the client settings, simulates a device :

private static String appBuild = "IOS_9289"; private static String appVersion = "6.1.6 (9289) #8fee5f53c-mod"; private static String osVersion = "14.4"; private static String deviceIdentifier = "iPhone11,8"; private static String clientName = "iPhone la"; private static String clientOs = "ios";

When login goes through, a pin code verification is sent.

Verify using /api/v4/account//client//pin/verify