Invalidate XSTS tokens rejected before NotAfter - #37
Conversation
|
This shouldn't normally happen if |
|
Token.Valid already checks that the token is non-empty, has user claims, and is before NotAfter with the existing one-minute refresh margin. In this incident the cached token had NotAfter 06:45 UTC but Profile and MPSD returned 401 error=token_expired around 03:20 UTC—roughly 3.5 hours early—while Social still accepted the same token with 200 OK. That rules out ordinary clock/expiry skew and shows service-side invalidation that cannot be predicted from the token fields. This path makes no additional request while Token.Valid succeeds normally. It only refreshes after an Xbox service has authoritatively rejected the token with the explicit token_expired challenge, and it retries at most once. Increasing the local margin enough to cover this sample would discard every token hours early and still would not handle arbitrary or service-specific revocation. If there is another client-observable signal available before the request, I can incorporate it, but I do not think Token.Valid alone can represent this case. |
Summary
401that explicitly reportserror=token_expirednsal.TokenInvalidatorcapabilitytoken_expiredchallengesThe expiry detection lives in the shared NSAL transport, so all authenticated Xbox API clients can discard a rejected cached token. Callers that need immediate replay can wrap
xsapi.Client.HTTPClient()with an outer retry client such as go-retryablehttp; callers without retry logic recover on their next normal request. Other401responses retain their existing behavior.Root cause
XSAPI considered the cached XSTS token valid using its signed
NotAftervalue. Xbox nevertheless rejected it early, so subsequent requests kept reusing the same locally valid token. Refreshing only after local expiration could not recover.Production evidence
These are sanitized observations from
mcxboxbroadcastinna-east-2; tokens, user hashes, and account identifiers are omitted.The cached token claimed another ~3.5 hours of validity:
Xbox rejected that token on independently authenticated services:
At the same time,
social.xboxlive.comaccepted the token with200 OK. This demonstrated that localNotAftervalidation alone is insufficient.For the controlled recovery, the Java broadcaster cache was backed up and only its root
xboxLiveXstsTokenentry was removed. The same Java build then fetched fresh SISU/XSTS state and logged: