fix: back to stateless refresh (sync endpoint)

This commit is contained in:
devthejo 2025-06-30 12:36:50 +02:00
parent b10ff5a6e7
commit 6af58755c1
2 changed files with 156 additions and 0 deletions

View file

@ -79,6 +79,50 @@ export default async function trackLocation() {
// Throttling configuration for auth reload only // Throttling configuration for auth reload only
const AUTH_RELOAD_THROTTLE = 5000; // 5 seconds throttle const AUTH_RELOAD_THROTTLE = 5000; // 5 seconds throttle
// The core auth reload function that will be throttled
async function _reloadAuth() {
locationLogger.info("Refreshing authentication token via sync endpoint");
try {
// Get current auth state to check if we have an auth token
const { authToken, userToken } = getAuthState();
if (!authToken) {
locationLogger.warn("No auth token available for refresh");
return;
}
locationLogger.debug(
"Auth token available, updating BackgroundGeolocation config",
);
// Update BackgroundGeolocation config to include X-Auth-Token header
await BackgroundGeolocation.setConfig({
headers: {
Authorization: `Bearer ${userToken}`, // Keep existing user token (may be expired)
"X-Auth-Token": authToken, // Add auth token for refresh
},
});
// Trigger sync to refresh token
await BackgroundGeolocation.changePace(true);
await BackgroundGeolocation.sync();
locationLogger.info("Token refresh sync triggered successfully");
} catch (error) {
locationLogger.error("Failed to refresh authentication token", {
error: error.message,
stack: error.stack,
});
}
}
// Create throttled version of auth reload with lodash
const reloadAuth = throttle(_reloadAuth, AUTH_RELOAD_THROTTLE, {
leading: true,
trailing: false, // Prevent trailing calls to avoid duplicate refreshes
});
// Handle auth function - no throttling or cooldown // Handle auth function - no throttling or cooldown
async function handleAuth(userToken) { async function handleAuth(userToken) {
locationLogger.info("Handling auth token update", { locationLogger.info("Handling auth token update", {
@ -236,6 +280,92 @@ export default async function trackLocation() {
status: statusCode, status: statusCode,
responseText: response?.responseText, responseText: response?.responseText,
}); });
switch (statusCode) {
case 200:
// Successful response, check for token refresh
try {
const responseBody = response?.responseText
? JSON.parse(response.responseText)
: null;
if (responseBody?.userBearerJwt) {
locationLogger.info(
"Token refresh successful, updating stored token",
);
// Use auth action to update both in-memory and persistent storage
await authActions.setUserToken(responseBody.userBearerJwt);
// Update BackgroundGeolocation config with new token
await BackgroundGeolocation.setConfig({
headers: {
Authorization: `Bearer ${responseBody.userBearerJwt}`,
},
});
locationLogger.debug(
"Updated BackgroundGeolocation with refreshed token and removed X-Auth-Token header",
);
Sentry.addBreadcrumb({
message: "Token refreshed successfully",
category: "geolocation-auth",
level: "info",
});
}
} catch (e) {
locationLogger.debug("Failed to parse successful response", {
error: e.message,
responseText: response?.responseText,
});
}
break;
case 410:
// Auth token expired, logout
locationLogger.info("Auth token expired (410), logging out");
Sentry.addBreadcrumb({
message: "Auth token expired - logging out",
category: "geolocation-auth",
level: "warning",
});
authActions.logout();
break;
case 401:
// Unauthorized: User token expired, refresh using throttled reload
locationLogger.info("Unauthorized (401), attempting to refresh token");
// Add more detailed logging of the error response
try {
const errorBody = response?.responseText
? JSON.parse(response.responseText)
: null;
locationLogger.debug("Unauthorized error details", {
errorBody,
errorType: errorBody?.error?.type,
errorMessage: errorBody?.error?.message,
errorPath: errorBody?.error?.errors?.[0]?.path,
});
Sentry.addBreadcrumb({
message: "Unauthorized - refreshing token",
category: "geolocation-auth",
level: "warning",
data: {
errorType: errorBody?.error?.type,
errorMessage: errorBody?.error?.message,
},
});
} catch (e) {
locationLogger.debug("Failed to parse error response", {
error: e.message,
responseText: response?.responseText,
});
}
reloadAuth();
break;
}
}); });
try { try {

View file

@ -275,6 +275,31 @@ export default createAtom(({ get, merge, getActions }) => {
triggerReload(); triggerReload();
}; };
const setUserToken = async (userToken) => {
authLogger.info("Setting user token", {
hasToken: !!userToken,
});
try {
// Update secure storage
await secureStore.setItemAsync("userToken", userToken);
// Update in-memory state
merge({ userToken });
// Update session from JWT
if (userToken) {
const jwtData = jwtDecode(userToken);
sessionActions.loadSessionFromJWT(jwtData);
}
authLogger.debug("User token updated successfully");
} catch (error) {
authLogger.error("Failed to set user token", { error: error.message });
throw error;
}
};
return { return {
default: { default: {
userToken: null, userToken: null,
@ -294,6 +319,7 @@ export default createAtom(({ get, merge, getActions }) => {
logout, logout,
onReload, onReload,
userOnMode, userOnMode,
setUserToken,
}, },
}; };
}); });