Description
[REQUIRED] Describe your environment
- Operating System version: Node.js v18.15.0
- Browser version: React-native v0.71.3 | Expo SDK 48
- Firebase SDK version: Firebase v9.17.2
- Firebase Product: auth
[REQUIRED] Describe the problem
It was working fine before, but after I updated Expo SDK from 46.0.0
to 48.0.0
and react-native from 0.69.6
to 0.71.3
, the authentication persistence wasn't working anymore. I was required to log in every time I opened the app to connect.
I tried to force persistence by using reactNativeLocalPersistence
but was returning an undefined
, only inMemoryPersistence
returned a value
So I realized that, since react-native v0.71.x Async-storage
was removed from react-native and actually, firebase is using that Async-Storage
from react-native to persist authentications
Steps to reproduce:
By using the following environment, you should get the same behavior:
- Node.js v18.15.0
- React-native v0.71.3 ( and Expo SDK 48 if you're using expo)
- Firebase v9.17.2
Then try to use the authentication system, to log in with Email and password, for example, you'll notice the auth persistence will not work. The current User will be lost when the app activity will be destroyed.
Relevant Code:
Here is the class I used to manage my firebase logic
class FirebaseHelper {
private app: FirebaseApp;
constructor() {
this.init();
}
/**
* Init firebase app
*
* @returns void
*/
init = () => {
if (!this.app) {
this.app = initializeApp({
apiKey: ENV.FIREBASE_CONFIG.apiKey,
authDomain: ENV.FIREBASE_CONFIG.authDomain,
projectId: ENV.FIREBASE_CONFIG.projectId,
storageBucket: ENV.FIREBASE_CONFIG.storageBucket,
messagingSenderId: ENV.FIREBASE_CONFIG.messagingSenderId,
appId: ENV.FIREBASE_CONFIG.appId,
measurementId: ENV.FIREBASE_CONFIG.measurementId,
});
}
};
/**
* Method to get the Firebase App
*/
getApp = () => {
return this.app;
};
/**
* Sign-up user and sign-in user
*
* @param form `SignUpFormType` object that contains new user data
*/
async signUp(form: SignUpFormType): Promise<boolean> {
const _VALIDATION_CONSTRAINT = {
username: {
...REQUIRE_NOT_EMPTY_PRESENCE,
length: {
maximum: 15,
},
},
email: REQUIRE_EMAIL,
password: {
...REQUIRE_NOT_EMPTY_PRESENCE,
length: {
minimum: 6,
},
},
amount: REQUIRE_NUMERIC,
confirmPassword: {
equality: 'password',
},
};
const _VALIDATION_RESULT = validate(form, _VALIDATION_CONSTRAINT);
if (_VALIDATION_RESULT) {
const _ERR_KEYS: string[] = [];
Object.keys(_VALIDATION_RESULT).map((key) => _ERR_KEYS.push(key));
showMessage({
type: 'danger',
message: _ERR_KEYS[0],
description: _VALIDATION_RESULT[_ERR_KEYS[0]][0],
});
return false;
}
try {
const _USER_CREDENTIALS = await createUserWithEmailAndPassword(
this.auth,
form.email,
form.password,
);
if (_USER_CREDENTIALS.user) {
const DEFAULT_PERIOD = SUPPORTED_PERIODS[0];
const _USER_DOC_REF = doc(this.db, 'users', _USER_CREDENTIALS.user.uid);
const _USER_GOAL_DOC_REF = doc(
this.db,
'users_goals',
_USER_CREDENTIALS.user.uid,
);
const _NEW_USER_DATA: NewUserDataInterface = {
email: form.email,
name: form.username,
photoURL: _USER_CREDENTIALS.user.photoURL || '',
phoneNumber: _USER_CREDENTIALS.user.phoneNumber || '',
signUpMethod: 'EmailAndPassword',
deleted: false,
createdAt: Timestamp.now(),
updatedAt: Timestamp.now(),
};
const _NEW_USER_GOAL_DATA: NewUserGoalDataInterface = {
amount: 0,
amount_goal: parseInt(form.amount, 10),
...DEFAULT_PERIOD,
user: _USER_DOC_REF,
startAt: Timestamp.now(),
createdAt: Timestamp.now(),
updatedAt: Timestamp.now(),
};
await setDoc(_USER_DOC_REF, _NEW_USER_DATA);
await setDoc(_USER_GOAL_DOC_REF, _NEW_USER_GOAL_DATA);
await this.setUpUserCharity({
user: _USER_DOC_REF,
});
showMessage({
type: 'success',
message: '🎉 Sign up successfully',
});
return true;
}
} catch (err) {
console.warn('🚧 FirebaseHelper->signUp->catch', err);
showMessage({
type: 'danger',
message: 'Something went wrong',
});
}
return false;
}
/**
* Sign-in user
*
* @param form
*/
async signIn(
form: SignInFormType,
showSuccessMessage: boolean = true,
): Promise<boolean> {
try {
const _USER_CREDENTIAL = await signInWithEmailAndPassword(
this.auth,
form.email,
form.password,
);
if (_USER_CREDENTIAL.user) {
if (await this.userDataExist(_USER_CREDENTIAL.user.uid)) {
showSuccessMessage &&
showMessage({
type: 'success',
message: '🎉 Connected successfully',
});
return true;
}
showMessage({
type: 'danger',
message: "🤔 It looks like you don't exist in our system",
duration: 3500,
});
}
} catch (err) {
console.warn('🚧 FirebaseHelper->signIn->catch', err);
}
return false;
}
// Other methods ...
/**
* Getter that simply returns a Firestore instance
* @returns {Firestore}
*/
get db(): Firestore {
return getFirestore(this.app);
}
/**
* Get an Auth instance
*
* @returns {Auth}
*/
get auth(): Auth {
return getAuth(this.app);
}
}
📌 Note
Actually, I just downgraded my react-native version to0.70.5
and my expo SDK to47
to make things work as expected