Refactor clear auth flows (#1404)

This commit is contained in:
Leendert de Borst
2026-01-19 12:19:03 +01:00
parent 4ffc8812b7
commit 575094aaab
2 changed files with 46 additions and 90 deletions
@@ -65,49 +65,18 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
setUsername(username);
}, []);
/**
* Clear authentication data and tokens from storage (user-initiated logout).
* This is called when the user explicitly clicks the logout button.
*
* @param errorMessage Optional error message to display on the login page
*/
const clearAuthUserInitiated = useCallback(async (errorMessage?: string) : Promise<void> => {
// Clear session data (tokens + ephemeral data)
await sendMessage('CLEAR_SESSION', {}, 'background');
// Clear vault data (vault + username)
await sendMessage('CLEAR_VAULT_DATA', {}, 'background');
// Clear in-memory database reference
dbContext?.clearDatabase();
// Clear PIN unlock data (if any)
try {
await removeAndDisablePin();
} catch (error) {
console.error('Failed to remove PIN data:', error);
// Non-fatal error - continue with logout
}
// Set local storage global message that will be shown on the login page.
if (errorMessage) {
setGlobalMessage(errorMessage);
}
setUsername(null);
}, [dbContext]);
/**
* Clear authentication data and tokens from storage (forced logout).
* This is called when the server forces a logout (401, token revocation, password change).
* Preserves the encrypted vault + metadata for recovery on next login.
*
* Keeps username for login page prefill and vault ownership verification.
*
* This is the base logout function. clearAuthUserInitiated builds on top of this.
*
* @param errorMessage Optional error message to display on the login page
*/
const clearAuthForced = useCallback(async (errorMessage?: string) : Promise<void> => {
// Only clear session data - vault data is preserved for recovery
// Clear session data (tokens + ephemeral data) - vault data is preserved for recovery
await sendMessage('CLEAR_SESSION', {}, 'background');
// Clear in-memory database reference
@@ -121,12 +90,30 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
// Non-fatal error - continue with logout
}
// Set local storage global message that will be shown on the login page.
// Set global message that will be shown on the login page
if (errorMessage) {
setGlobalMessage(errorMessage);
}
}, [dbContext]);
/**
* Clear authentication data and tokens from storage (user-initiated logout).
* This is called when the user explicitly clicks the logout button.
*
* Builds on clearAuthForced by also clearing vault data and username.
*
* @param errorMessage Optional error message to display on the login page
*/
const clearAuthUserInitiated = useCallback(async (errorMessage?: string) : Promise<void> => {
// First, perform the base forced logout (clears session, in-memory db, PIN)
await clearAuthForced(errorMessage);
// Additionally clear vault data and username (forced logout preserves these for recovery)
await sendMessage('CLEAR_VAULT_DATA', {}, 'background');
setUsername(null);
}, [clearAuthForced]);
/**
* Clear global message (called after displaying the message).
*/
+24 -55
View File
@@ -188,58 +188,12 @@ export const AuthProvider: React.FC<{
setIsLoggedIn(true);
}, []);
/**
* Clear authentication data for user-initiated logout (e.g., user clicks logout button).
* Clears ALL data including vault - user explicitly chose to logout.
*/
const clearAuthUserInitiated = useCallback(async (errorMessage?: string): Promise<void> => {
// Clear credential identity store (password and passkey autofill metadata)
try {
await NativeVaultManager.removeCredentialIdentities();
} catch (error) {
console.error('Failed to remove credential identities:', error);
// Non-fatal error - continue with logout
}
// Clear PIN unlock data (if any)
try {
await NativeVaultManager.removeAndDisablePin();
} catch (error) {
console.error('Failed to remove PIN data:', error);
// Non-fatal error - continue with logout
}
// Clear from native layer
await NativeVaultManager.clearUsername();
await NativeVaultManager.clearAuthTokens();
// Clear from AsyncStorage (for backward compatibility)
// TODO: Remove AsyncStorage cleanup in future version 0.25.0+
await AsyncStorage.removeItem('username');
await AsyncStorage.removeItem('accessToken');
await AsyncStorage.removeItem('refreshToken');
await AsyncStorage.removeItem('authMethods');
// Clear ALL vault data - user explicitly chose to logout
dbContext?.clearDatabase();
if (errorMessage) {
// Show alert
Alert.alert(
i18n.t('common.error'),
errorMessage,
[{ text: i18n.t('common.ok'), style: 'default' }]
);
}
setUsername(null);
setIsLoggedIn(false);
}, [dbContext]);
/**
* Clear authentication data for forced logout (e.g., 401 error, token revocation).
* Preserves vault data for potential RPO recovery - user didn't choose to logout.
* The vault will be recovered on next login if the password hasn't changed.
*
* This is the base logout function. clearAuthUserInitiated builds on top of this.
*/
const clearAuthForced = useCallback(async (errorMessage?: string): Promise<void> => {
// Clear credential identity store (password and passkey autofill metadata)
@@ -258,20 +212,15 @@ export const AuthProvider: React.FC<{
// Non-fatal error - continue with logout
}
// Clear auth tokens only - preserve vault data for recovery
// Clear auth tokens and session in native layer (preserves vault data)
await NativeVaultManager.clearAuthTokens();
// Clear session in native layer (preserves vault data)
await NativeVaultManager.clearSession();
// Clear from AsyncStorage (for backward compatibility)
// TODO: Remove AsyncStorage cleanup in future version 0.25.0+
await AsyncStorage.removeItem('accessToken');
await AsyncStorage.removeItem('refreshToken');
await AsyncStorage.removeItem('authMethods');
await AsyncStorage.multiRemove(['accessToken', 'refreshToken', 'authMethods']);
if (errorMessage) {
// Show alert
Alert.alert(
i18n.t('common.error'),
errorMessage,
@@ -282,6 +231,26 @@ export const AuthProvider: React.FC<{
setIsLoggedIn(false);
}, []);
/**
* Clear authentication data for user-initiated logout (e.g., user clicks logout button).
* Clears ALL data including vault - user explicitly chose to logout.
*
* Builds on clearAuthForced by also clearing vault data and username.
*/
const clearAuthUserInitiated = useCallback(async (errorMessage?: string): Promise<void> => {
// First, perform the base forced logout (clears session, tokens, PIN, credentials)
await clearAuthForced(errorMessage);
// Additionally clear username (forced logout preserves it for login prefill)
await NativeVaultManager.clearUsername();
await AsyncStorage.removeItem('username'); // TODO: Remove in 0.25.0+
// Clear ALL vault data - user explicitly chose to logout
dbContext?.clearDatabase();
setUsername(null);
}, [dbContext, clearAuthForced]);
/**
* Set the authentication methods and save them to storage
*/