I'm using content scripts
I have created a chrome extension that will run on any number of domains where i have no control, and the extension uses Firebase login through a content-script.
My issue is that it seems like Firebase persists the state by using the indexedDB, but that makes the extension vulnerable to malicious websites stealing the user session by reading the indexedDB state (perhaps i am wrong here?).
When the extension is activated I inject a tiny react app into the DOM through a content-script which uses the Firebase javacript sdk to get data and manage login sessions. I would like for the login state of the users to be persisted so they don't have to log in every time they use the extension (otherwise i guess i could just set Firebase persistence to NONE to prevent it from using indexedDB).
Im thinking that if i can somehow save the session (refreshToken perhaps) in the chrome storage area, and then read it on load to reinitialize a user-session, then the session is more secure (not very secure, but more secure than if i use the indexedDB). Even tho the storage area is accessible by entering the right folder on the PC, its seems like a better deal to have data stored there where only the extension can access it programmatically.
Things i have tried so far
Manual way
I have tried using an endpoint with an apiKey and refresh token to get new credentials (ref: How to use the Firebase refreshToken to reauthenticate?) and this works fine. I have also been able to get the refreshToken from the user object returned after doing signInWithEmailAndPassword().
So the last piece of the puzzle is to pipe this refreshed login state into the Firebase sdk to be able to use the firebase sdk features like change listeners etc. But I have not found a way of doing this. Does anyone know if this is possible?
Built in method
There is a method called signInAndRetrieveDataWithCredential that i have tried to use. The login function returns a credential object that I have tried to pass in to signInAndRetrieveDataWithCredential to resume the user session, but the method returns an error saying the object is invalid. There is probably alot of things that should not be persisted in the credential object so this is not the preferred way, but as a last resort I could see this as an option. But as a more general question about Firebase, is there a way to keep the users logged in and store it in a place like chrome.storage?
The worst way
Persisting username/password in chrome storage is possible and would give the extension the option to sign the user in as they open it. This is of course a horrible way of going around the issue and is not really an option. But I have read that the chrome password manager also stores passwords relatively insecure, so whats the difference between that and storing password for this extension in chrome storage with perhaps some obfuscation step to prevent it from being clearly readable?
** UPDATE **
To work around this issue i have created an endpoint for validating and logging users in using custom tokens. It works as follows:
- User signs in, store refreshToken in chrome.storage.sync
- when a user starts the addon for the second time i fetch the token from the chrome storage.async
- post the token to a Firebase function i created that uses the method for refreshing a token described in the section "Manual way" above.
- If i get a positive result when calling the authenticate endpoint from my Firebase function i assume the token was valid and use the userId in the data returned to create a custom token that is sent back to the user
- Use this custom token to sign the user in by calling
firebase.auth().signInWithCustomToken(token)
- Use this custom token to sign the user in by calling
Custom token link: https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_the_firebase_admin_sdk
However the questions above still remain:
- Is it possible to store a user session other than in the context of firebase persist, and then "activate" the user session again using this session-data when a user comes back? something like
signInWithRefreshToken? - Is there a built in way to keep the users signed in and store it in a place like chrome.storage? (answer seems to be no).
- Is there a way to store obfuscated user signin info in a chrome.storage.sync that can be considered to be safe enough? The info is used on page load and deleted when the credentials are no longer valid or the user signs out.
**SECOND UPDATE **
When i run the following script on a testsite hosted on Firebase and with the extension installed locally and not throught the chrome web store, i get the persisted firebase session including refresh token:
const request = window.indexedDB.open("firebaseLocalStorageDb", 1);
request.onerror = function (event) {
console.err("error fetching data", event);
};
request.onsuccess = function (dbEvent) {
const db = request.result;
const transaction = db.transaction(["firebaseLocalStorage"]);
console.log({transaction});
const objectStore = transaction.objectStore("firebaseLocalStorage");
if ('getAll' in objectStore) {
objectStore.getAll().onsuccess = function (getAllEvent) {
console.log(event.target.result);
};
}
};
In addition, when i inspect the indexeddb using the debugger window the indexeddb of the extension has the security origin set to the page it is loaded through.
screnshot of the security origin in the chrome debugger window