Skip to content

Offer a fresh login when saved credentials stop working - #1029

Open
sjbrownrigg wants to merge 1 commit into
nathom:devfrom
sjbrownrigg:fix/reauth-prompt-on-expired-token
Open

Offer a fresh login when saved credentials stop working#1029
sjbrownrigg wants to merge 1 commit into
nathom:devfrom
sjbrownrigg:fix/reauth-prompt-on-expired-token

Conversation

@sjbrownrigg

Copy link
Copy Markdown

Problem

has_creds() only checks that a credential is stored, not that it still works:

def has_creds(self) -> bool:
    return len(self.config.session.tidal.access_token) > 0

An expired token is still a non-empty string. So the check passes, login() is
attempted, and the failure surfaces as a bare traceback — even though the
prompter that would fix it is already built, and is reached in the
has_creds() == False branch a few lines above.

For Tidal the two failure points were untyped, so nothing could catch them
precisely:

raise Exception("Access token not found in config.")   # never set up
raise Exception("Refresh failed")                      # refresh token lapsed

The second is the common one. Tidal access tokens are refreshed automatically,
but the refresh token eventually expires too, and when it does there is
nothing left to refresh from. Today that ends in:

TypeError: 'NoneType' object does not support the context manager protocol

Change

get_logged_in_client() catches AuthenticationError and
MissingCredentialsError from login() and offers a fresh login.

Qobuz and Deezer already raise those types, so the only change needed to cover
all three sources was giving Tidal's two bare Exceptions the same types.

Declining re-raises the original error, so nothing is swallowed.

Non-interactive runs never prompt. rip is used from cron and from
scripts, where a hidden y/n hangs forever instead of failing. Without a tty it
raises with an explanation instead, following the sys.stdin.isatty() guard
already used for artist album selection.

Relationship to #955

#955 by @mikelandzelo173 got here first and modifies the same lines,
wrapping await client.login() in try/except AuthenticationError. Its
handler is deliberately Qobuz-only:

except AuthenticationError:
    if source != "qobuz":
        raise

That PR's real subject is the new Qobuz token flow; this one takes the same
idea and generalises it — every source, both credential exception types, and a
guard for non-interactive use.

These will conflict. They should not both be merged as-is. If #955 lands
first I am happy to rebase this on top and reduce it to the generalisation, or
to close it if the Qobuz-specific form is preferred. Flagging it rather than
letting a merge conflict be the discovery.

Testing

tests/test_reauth_prompt.py covers three paths — accept, decline, and no
tty — and each fails without this change.

3 passed

Full suite: 62 passed, 7 skipped. tests/test_meta.py::test_album_metadata_qobuz
fails, but it fails identically on unmodified dev.

has_creds() only checks that something is stored, not that it still
works. An expired token is still a non-empty string, so the check
passes, login() is attempted, and the failure surfaced as a bare
traceback -- even though the prompter that fixes it is already built and
reached in the has_creds() == False branch a few lines above.

get_logged_in_client now catches AuthenticationError and
MissingCredentialsError from login() and offers to re-authorise. Qobuz
and Deezer already raise those types, so the only change needed to cover
all three sources was typing Tidal's two bare Exceptions -- 'Access
token not found in config.' and 'Refresh failed', the latter being what
you get when the refresh token itself lapses.

Declining re-raises the original error, so nothing is swallowed.

Non-interactive runs never prompt. rip is used from cron and from
scripts, where a hidden y/n hangs forever instead of failing, so without
a tty it raises with an explanation of what to do. This follows the
isatty guard already used for artist album selection.

Tests cover all three paths and fail without the change.
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

Successfully merging this pull request may close these issues.

1 participant