fix: back to stateless refresh (sync endpoint)
This commit is contained in:
parent
b10ff5a6e7
commit
6af58755c1
2 changed files with 156 additions and 0 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue