Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentication failed (ewelink-api) #242

Open
SpoedNick80 opened this issue Nov 18, 2024 · 14 comments
Open

Authentication failed (ewelink-api) #242

SpoedNick80 opened this issue Nov 18, 2024 · 14 comments

Comments

@SpoedNick80
Copy link

Hi all,

I have been using the ewelink node api for more than a year now on my solar home automation system. Been working flawless, but now the api returns 'Authentication failed'. I noticed my Authorization Key expired on https://dev.ewelink.cc. I deleted the old app created a new one and started using the new APP_ID and APP_SECRET. Its been more than a week now and its still not working. Has there been changes to the API or something i'm not aware of?

Thanks for any help in advance.
lou

@garikou
Copy link

garikou commented Nov 20, 2024

Similar issue here but API key has not expired for me, but I get a 407 path request not allowed for any endpoint that was already working before. Created a ticket and they sent me to talk to [email protected], no reply from them for the last 5 days.

@NickWaterton
Copy link

Same problem here. Created a new APP_ID and APP_SECRET (even though previous had not expired), but same message:

407 path request not allowed for appid:xxxxxxxxxxxxxxxxxxxxxx

Looks like something changed.

@garikou
Copy link

garikou commented Dec 11, 2024 via email

@NickWaterton
Copy link

NickWaterton commented Dec 11, 2024

Well that’s super annoying.

when they say “login manually”, do they mean just send your login and password to get the token? I can’t see why you would have to specifically use the web interface.

I see they have a getToken endpoint, that expects a url to be passed - do you think this is what they are talking about?

@garikou
Copy link

garikou commented Dec 11, 2024 via email

@NickWaterton
Copy link

I have a feeling they don’t know what they are talking about. There is no need to have an actual web page for people to fill in.

I’ve read their docs, the problem is that most of them are out of date, or don’t actually work.

I’ll figure it out.

@garikou
Copy link

garikou commented Dec 11, 2024 via email

@SpoedNick80
Copy link
Author

It seems the api only supports oauth2 now. I wrote an application in Python to fetch the oath token. Then with the token I'm able to get status/update/stop/start devices. I am by no mean a developer by trade, but if your stuck let me know and I can upload the code here....

@NickWaterton
Copy link

@SpoedNick80 If you have some code that gets the token without using the /v2/user/login end point I would certainly be interested.

Feel free to upload a snippet.

@Husseinhassan1
Copy link

@SpoedNick80 Would you be able to share the code? It's my first time using this library and I couldn't get even the basic example from the documentation to work as I am getting this error

@NickWaterton
Copy link

@Husseinhassan1 This is the problem, this library won’t work anymore, as they have moved the login end point to be an enterprise feature.

@NickWaterton
Copy link

NickWaterton commented Dec 31, 2024

Ok, so I figured out how to get the code (without the login page), I can pass that to get token and successfully get the access and refresh tokens.

Problem is when you use this access token to try to get the apikey you get the same error messagepath not allowed for app id:xxxxxxxxxxxxxxxxx.

So, I’m still stuck. I can query devices, homes etc, but you can’t connect to the websocket without the apikey.

@NickWaterton
Copy link

NickWaterton commented Jan 2, 2025

So, I finally have it working again.

The process is:

  1. Obtain the access code
  2. exchange the access code for an access token
  3. get the family data to obtain the apikey
  4. open the websocket using the obtained apikey and access token

To get the access code (without using the login page) - sorry this is Python:
APP = [(appid, clientsecret)]
redirectUrl is the redirect url you defined in the developer console for the app - it is NOT USED, so it can be whatever you want, but it has to match. I used "https://127.0.0.1:8888"
helper methods:

    def makeSign(self, key, message):
        j = hmac.new(key.encode(), message.encode(), digestmod=hashlib.sha256)
        return (base64.b64encode(j.digest())).decode()

    def get_nonce(self):
        ts = time.time()
        return str(int(ts))[-8:]
        
    def get_ts(self):
        '''
        gets timestamp in ms as string
        '''
        return str(int(time.time()* 1000))
    async def get_code(login, password, app=0):
        appid, appsecret = APP[app]
        seq = self.get_ts()
        nonce = self.get_nonce()
        state = '12345'
        sign = self.makeSign(appsecret, '{}_{}'.format(appid, seq))
        payload =   {   'authorization' : 'Sign ' + sign,
                        "email" : login,
                        "password" : password,
                        'seq': seq,
                        'clientId': appid,
                        "state" : state,
                        "grantType" : "authorization_code",
                        'redirectUrl':redirectUrl,
                        "nonce" : nonce
                    }
        data = json.dumps(payload).encode()
        headers =   {   "X-CK-Appid": appid,
                        "X-CK-Nonce": nonce,
                        "X-CK-Seq": seq,
                        "Authorization": "Sign " + sign,
                        "Content-Type": "application/json; charset=utf-8"
                    }    
        url = "https://apia.coolkit.cn/v2/user/oauth/code"
        self.log.info('Logging in via: {} with {} and {}'.format(url, appid, appsecret))
        r = await self.session.post(
            url, data=data, headers=headers,
            timeout=30
        )
        resp = await r.json()
        return resp['data']

the access code is in resp.
To get the access token from the access code:

    async def get_token(self, code, app=0):
        '''
        get token from code
        '''
        appid, appsecret = APP[app]
        payload = { "code": code,
                    "redirectUrl":redirectUrl,
                    "grantType":"authorization_code"
                  }
        data = json.dumps(payload).encode()
        sign = self.makeSign(appsecret, json.dumps(payload))
        headers =   {   "X-CK-Appid": appid,
                        "X-CK-Nonce": self.get_nonce(),
                        "Authorization": "Sign " + sign,
                        "Content-Type": "application/json; charset=utf-8"
                    }
        self.host = "https://us-apia.coolkit.cc" #depends on region (returned with code)
        url =  self.host + '/v2/user/oauth/token'
        self.log.info('Getting token via: {} with code: {}'.format(url, code))
        r = await self.session.post(
            url, data=data, headers=headers,
            timeout=30
        )
        resp = await r.json()
        return resp['data']

The access token, refresh token and expiry dates (in timestamp milliseconds) are returned.
To get the apikey using the access token:

    async def _get(self, token, app = 0):
        headers = { "Authorization": "Bearer " + token,
                    "X-CK-Appid": APP[app][0]}
        r = await self.session.get(
            self.host + '/v2/family', headers=headers, timeout=5
        )
        resp = await r.json()
        return resp['data']

The apikey is contained in the returned json, and can be used to open and connect to the websocket.

Sorry this is a bit rough, and in Python, but hopefully you understand the sequence.

@gbsallery
Copy link

@NickWaterton that's extremely helpful, thank you. Can confirm that your approach works when implemented in Kotlin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants