tamland / python-tidal

Python API for TIDAL music streaming service
GNU Lesser General Public License v3.0
402 stars 108 forks source link

Oauth2 logins not working #65

Closed trumpeta closed 1 year ago

trumpeta commented 3 years ago

tidalapi v0.7.0 Rewrite

import tidalapi
session = tidalapi.Session()
session.login_oauth()

generates HTTP 400/authorization_pending error resulting to "You took too long to log in" exception. Is there something wrong on client side or is the method not yet ready?

trumpeta commented 3 years ago

I'm afraid there's an extra interactive step required, not implemented yet (ie. filling in login/password or resolving captcha), like the web interface does. That would make the Oauth login not unattended and break many automated tasks.

The thrown "You took too long to log in" reason foreshadows that.

divadsn commented 3 years ago

The example suggests using session.login_oauth_simple()?

trumpeta commented 3 years ago

session.login_oauth_simple works, unlike login_oauth it prints out a web link, which copied to browser allows to link the request to account. I was able to receive valid auth token which seems to persist for one week, then refreshed for another week, but after both periods expire, most probably I will be asked re-authorize (by hand) again and again, which comes a bit annoying, especially for unattended tasks.

Would it be possible to perform the authorization step by API also?

divadsn commented 3 years ago

That's why you have a refresh token, as together with the session ID you're able to get a new access token without having to log in again.

pon., 19 kwi 2021, 13:12 użytkownik trumpeta @.***> napisał:

session.login_oauth_simple works, unlike login_oauth it prints out a web link, which copied to browser allows to link the request to account. I was able to receive valid auth token which seems to persist for one week, then refreshed for another week, but after both periods expire, most probably I will be asked re-authorize (by hand) again and again, which comes a bit annoying, especially for unattended tasks.

Would it be possible to perform the authorization step by API also?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/tamland/python-tidal/issues/65#issuecomment-822386500, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGZZWBZS3PMVIBK2E3XDO2DTJQF23ANCNFSM43C4747Q .

trumpeta commented 3 years ago

I assumed the refresh token can be used only once, as the complete access token returned by token_refresh() doesn't contain refresh_token key yet.

So the refresh_token returned by the initial login_oauth_simple() call is perpetual?

divadsn commented 3 years ago

https://github.com/tamland/python-tidal/issues/63#issuecomment-821204891

You're supposed only to call login once and then load all the values via load_oauth_login() from environment variables or config for example.

JuniorJPDJ commented 3 years ago

Refresh token can be used pretty long time. It's not in token_refresh result as it's the same as before, you need to use same - initial one. Tidal also provides another headless login method (DeviceFlow) which is more cool for embedding in apps so would be cool to have it implemented too.

EDIT: It seems this lib already uses DeviceFlow

tehkillerbee commented 3 years ago

What is the correct approach to use the refresh token after the session expires? And how can we detect if the session has indeed expired before attempting to stream?

divadsn commented 3 years ago

@tehkillerbee you don't need to worry about, refresh tokens have a long expiration period and if you need to check whether it has expired or not, then you simply parse with a JWT library and compare the timestamps.

Also: https://github.com/tamland/python-tidal/commit/ee120d94d897f6f6ee644fd835a35fb68942b331

JuniorJPDJ commented 3 years ago

@divadsn: @tehkillerbee is probably talking about refreshing auth token using refresh token

@tehkillerbee token is refreshed automagically starting from this commit: https://github.com/tamland/python-tidal/commit/ee120d94d897f6f6ee644fd835a35fb68942b331 as far as your refresh token is valid (eg. you didn't log out your session or changed password), it should JUST WORK (TM) you can also check what happens when you change password and try to use session and let us know, as this is interesting case

divadsn commented 3 years ago

@JuniorJPDJ refresh tokens are invalidated when you change password

JuniorJPDJ commented 3 years ago

@divadsn: this is what I already know, I'm curious what will be result in code. What exceptions will be thrown, if it would be easly distinguishible from other errors etc.

divadsn commented 3 years ago

@JuniorJPDJ you simply get a requests.exceptions.HTTPError raised, in which you can check the status code.

2021-05-18 01:13:49,449 - __NAME__ - WARNING - The refresh token has expired, a new login is required.
2021-05-18 01:13:49,449 - telethon.client.updates - ERROR - Unhandled exception on inline_handler
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/telethon/client/updates.py", line 454, in _dispatch_update
    await callback(event)
  File "/usr/src/app/tidalbot/tidalbot.py", line 201, in inline_handler
    search = self.session.search(query, [Track], limit=10)
  File "/usr/local/lib/python3.9/site-packages/tidalapi/session.py", line 426, in search
    json_obj = self.request.request('GET', 'search', params=params).json()
  File "/usr/local/lib/python3.9/site-packages/tidalapi/request.py", line 87, in request
    request.raise_for_status()
  File "/usr/local/lib/python3.9/site-packages/requests/models.py", line 943, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://api.tidal.com/v1/search?sessionId=xxx&countryCode=GB&limit=10&query=009+so&offset=0&types=tracks
tehkillerbee commented 3 years ago

@JuniorJPDJ Thanks for your explanation. Yes, I am talking about refreshing auth token using refresh token to avoid having to visit the login URL again.

Currently, I call load_oauth_session() given token_type, session_id, access_token and refresh_token from last login_oauth_simple() successful login. But as I understand, this approach does not work in the 0.6.8 version of python-tidal, as the access token is not refreshed automatically using the refresh token.

The above fix https://github.com/tamland/python-tidal/commit/ee120d94d897f6f6ee644fd835a35fb68942b331 only applies to 0.7.x, correct? Will a new version of 0.6.x be released to fix it as well? Otherwise, I will have to add an extra check in my mopidy-tidal plugin.

Also, I will try to test what happens when changing the password and let you know the results.

divadsn commented 3 years ago

@tehkillerbee I don't know if you haven't checked the branch history, but the commit is there as well: https://github.com/tamland/python-tidal/commit/d7a77f37257ba9892b77babe3cdf97268b5964e4

Edit: If you mean PyPI, there is no new version with the fix released yet

tehkillerbee commented 3 years ago

@divadsn Thanks, yes I shortly found that commit after posting my first comment. Anyways, after checking out the latest 0.6.x branch and updating tidalapi, my mopidy-tidal plugin works as expected without any changes. So I guess we just have to wait for an updated 0.6.x release :)

tehkillerbee commented 3 years ago

One more comment to add, it seems after streaming for a couple of hours (4-5 albums), the 401 Client Error: Unauthorized for URL appeared again and playback stopped abruptly.

After restarting Mopidy, I am prompted with another "Visit link.tidal.com/XXXXX to log in, the code will expire in 300 seconds"

Its definitely less than one week since I last had to authenticate.

JuniorJPDJ commented 3 years ago

So this means that autorefresh doesn't work? I've no trouble using the same refresh token with my lib for few months.

tehkillerbee commented 3 years ago

Well when the 401 client error appeared while requesting a song, the token was not refreshed automatically.

After restarting mopidy, it was not refreshed and a new auth was requested instead. So either the tokens I am loading from the json file are not valid - or the auto refresh is not triggered.

divadsn commented 3 years ago

@tehkillerbee my bot is using the latest 0.7x branch with same tokens for 11 days now without any issues.

image

Also, upon checking, the access tokens from Tidal are valid for one week, while the refresh tokens don't have a exp timestamp.

Regarding auto refresh, I think pip did not upgrade your local tidalapi package when installing via pip install -U git+https://github.com/tamland/python-tidal@0.6.x, as it still uses the old 0.6.8 release version inside setup.py.

Just uninstall the PyPI version first and then install from git, this should solve your problem.

tehkillerbee commented 3 years ago

@divadsn Thank you. I will try reinstalling tidalapi as you instructed and see if the issue reappears. Unfortunately, it takes a while to test :)

2e0byo commented 1 year ago

@tehkillerbee can we close this? Do we need to update the docs?

tehkillerbee commented 1 year ago

I suspect the issue was left open due to the documentation not being updated. But let's close it and add a new issue that describes how to load token from file.