Report a consumer the API no longer accepts - #108
Merged
Conversation
A long-running client renews its access token with reauthorize/3 when a
data endpoint answers 401. That works until the consumer expires as
well, which the API tends to do at the same nightly maintenance: from
then on the renewal fails and no retry gets anywhere, because only a new
consumer can, and registering one means calling login/3.
There was no way to tell that apart. /oauth1/request_token answers a
consumer it no longer accepts with a 400 and an empty body, so the
failure arrived as a bare {:http_error, 400}, indistinguishable from a
malformed request. Observed in production: an expired token at 03:52
followed by four hours of 400s, until a restart signed in from scratch.
The step now reports it as reason: :consumer_rejected, which is the
signal to call login/3. Only an empty body is mapped, so an error the
API bothered to write keeps its message, and both 400 and 401 are
covered because request_token takes no parameters of its own: the
consumer key and its signature are the only thing it can refuse.
Exception.message/1 gained clauses for :consumer_rejected and
:not_logged_in, which rendered as inspected atoms until now.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A long-running client renews its access token with
reauthorize/3when a data endpoint answers 401. That works until the consumer expires as well, which the API tends to do at the same nightly maintenance. From then on the renewal fails and no retry gets anywhere, because only a new consumer can help and registering one means callinglogin/3.There was no way to tell that apart.
/oauth1/request_tokenanswers a consumer it no longer accepts with a 400 and an empty body, so the failure arrived as a bare{:http_error, 400}, indistinguishable from a malformed request. My smartmeter deployment hit exactly this: the token expired at 03:52, then four hours of 400s at four-minute intervals until a restart signed in from scratch.The fix
get_request_token/2reports it asreason: :consumer_rejected, which is the signal to calllogin/3:Only an empty body is mapped, so an error the API bothered to write keeps its message. Both 400 and 401 are covered, because
request_tokenis posted with no parameters of its own: the consumer key and its signature are the only thing it can refuse.Exception.message/1also gained clauses for:consumer_rejectedand:not_logged_in, which rendered as inspected atoms (":consumer_rejected") in log lines until now.Verified against the API
Confirmed on the demo account, which is where the numbers below come from:
request_token, valid key and secret200request_token, valid key, wrong secret400, empty bodyrequest_token, unknown key400, empty bodymeters, unknown consumer401, empty bodySo the data endpoints use 401 for credentials they no longer accept, and this one uses 400. End to end, with a deliberately dead consumer, the documented recovery now works:
The ordinary path is unaffected:
login/3followed byreauthorize/3reuses the consumer and gets a fresh token, all three steps200.Docs
guides/api-quirks.mdgains a section on consumers expiring and the 400 that reports it, and the advice about persisting a consumer now says it can be rejected later. Thereauthorize/3docs carry the fallback snippet.One correction in there: the snippet passes the existing
clienttologin/3rather than a freshClient.new(). Since d7a1c7alogin/3discards the previous session's credentials itself, and reusing the client keeps its:base_urland:http_client, whichClient.new()would silently reset to the defaults.42 tests pass.