fix(shopinbit): re-authenticate once on HTTP 401
What changed, and why it matters
This commit fixes a bug in the Stack Wallet app's integration with ShopInBit. Previously, if the app's login token expired while making a request, the app would simply fail. Now, when it receives an HTTP 401 'unauthorized' error, it automatically refreshes the token once and retries the request. This is a routine reliability fix rather than a security vulnerability patch.
No security action required. This is a normal bug fix improving API reliability. Users should update to a version containing this commit if they experienced ShopInBit request failures due to expired sessions.
Security signals we found
Adds handling for HTTP 401 authentication failures
Invalidates and refreshes bearer token on auth failure
Limits re-authentication to a single retry to avoid infinite loops
Evidence from the diff
The change adds single-attempt token refresh logic in lib/services/shopinbit/src/client.dart. When an authenticated request returns HTTP 401, the client now invalidates the cached token via _tokenManager.invalidate(), obtains a new valid token, rebuilds the Authorization header, and retries the same request once before giving up. This prevents stale bearer tokens from causing unnecessary request failures.
Changed components
lib/services/shopinbit/src/client.dartShopInBit API clientBearer token authentication flowInspect captured patch +14 / −1
diff --git a/lib/services/shopinbit/src/client.dart b/lib/services/shopinbit/src/client.dart
index 19915cb..9bda1bc 100644
--- a/lib/services/shopinbit/src/client.dart
+++ b/lib/services/shopinbit/src/client.dart
@@ -607,7 +607,7 @@ class ShopInBitClient {
if (query != null && query.isNotEmpty) {
uri = uri.replace(queryParameters: query);
}
- final Map<String, String> headers;
+ Map<String, String> headers;
if (needsAuth) {
final token = await _tokenManager.getValidToken();
headers = _headers(token, customerKey: customerKey);
@@ -659,8 +659,21 @@ class ShopInBitClient {
// present, otherwise exponential backoff with jitter. Everything funnels
// through here, so all endpoints get this for free.
int attempt = 0;
+ bool reauthed = false;
while (true) {
final response = await dispatch();
+ // A 401 means the bearer token is stale/expired: invalidate it,
+ // re-authenticate once, and retry before surfacing the error.
+ if (response.code == 401 && needsAuth && !reauthed) {
+ reauthed = true;
+ _tokenManager.invalidate();
+ final token = await _tokenManager.getValidToken();
+ headers = _headers(token, customerKey: customerKey);
+ Logging.instance.w(
+ "$_kTag $method $resolved HTTP:401, re-authenticating",
+ );
+ continue;
+ }
if (response.code != 429 || attempt >= _kMaxRetries) {
return response;
}
Why this scored 22/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.