How do I persist user authentication using the Firebase refresh token? - javascript

I am building a React Native app which uses Firebase phone authentication for user login. Authentication works fine but the token expires after an hour. I have read that I need to use the refresh token to refresh the idToken, but nowhere on the Firebase docs does it explain how to do this. It only explains how to revoke refresh tokens, and I can't even find it.
I am using the react-native-firebase package.
My questions are: how to I get the refresh token, how do I use it, and do I really need to call Firebase every hour to update my idToken?
I am currently getting my idToken like this:
const authenticate = async (credential) => {
try {
const { user } = await firebase.auth().signInWithCredential(credential);
const accessToken = await user.getIdToken();
return accessToken;
} catch (error) {
console.log(error);
}
}
I then take the token and store it locally using AsyncStorage and check if the token exists every time the app is launched.
Thanks in advance.

From https://rnfirebase.io/reference/auth/user#getIdToken
It seems that using user.getIdToken() refresh the token if it has expired.
You can always use the forceRefresh option if you want to refresh the token even if it's still valid.

Related

Why Firebase (onAuthStateChanged) does not see a Google signup user (with signInWithCredential)?

So I followed this tutorial on how to sign in a user with rnfirebase and google signup. And it works fine. Here is the code:
const googleSignUp = async () => {
// Get the users ID token
const { idToken } = await GoogleSignin.signIn();
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
const user = auth().signInWithCredential(googleCredential);
return { idToken, user };
};
(Let me note here, that the app has already a sign in with email and password way, with Firebase).
Then I realized that the user cannot change his name, email or delete his account.
Looking deeper, I found out that the onAuthStateChanged(firebase.auth, async (user) => ... returns null for the user.
I've seen in some older answers that if you use Google sign up, you need to sign up the user with signInWithCredential, which I use, so this in not the issue.
Could it be a problem that for email/password sign in, I use code from Firebase web and not from rnfirebase? Although I already had a combination of those, using the push notifications from rnfirebase.
Can someone explain why I get this behavior, and how to fix it?
Thanks!
If I understand correctly, you use both the react-native-firebase library (which wraps the native iOS and Android SDKs) and the JavaScript Web SDK for Firebase in your app.
If that is the case, both indeed have a separate sign-in state, and signing into one won't fire onAuthStateChanged listeners on the other.
You'll have to pick one SDK to authenticate with Firebase, and then use that for both providers.

Firebase user is logged out on page reload | FirebaseAuthError: Decoding Firebase ID token failed

I am currently using firebase for auth in my web application and one particular issue that I have been facing is that even though the user did not sign out from the application if I reload the page and try to access the current user's accessToken using the following snippet of onAuthStateChanged
import { getAuth, onAuthStateChanged } from "firebase/auth";
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
const userAccessToken = user?.accesstoken;
doStuff(userAccessToken); // some placeholder function which takes the `userAccessToken` as one of the parameters
});
The user object is null thus indicating the user is signed out. How do I prevent this from happening? Is there a way to ensure that the user stays signed in unless he explicitly signs out from the application?
The onAuthStateChanged must always return the user as not null unless he signs out. The page reloads or any other kind of navigation or operations must not affect this state.
This has particularly been a problem since I require the jwt token of the currently signed-in user to carry out authorization tasks in the backend. The firebase-admin function
const decodedToken = await admin.auth().verifyIdToken(authJwtToken);
upon receiving null errors out
FirebaseAuthError: Decoding Firebase ID token failed. Make sure you passed the entire string JWT which represents an ID token.

how to reauthenticate user with firebase authentication?

I'm new to firebase.
In my nuxt js project with multiple pages, firestore rule is set to read or write once request.auth != null.
so if when refresh in a page, auth will be gone and it display error 'permission-denied' in terminal.
i tried Authentication State Persistence LOCAL but it doesn't work.
What is the purpose of using these auth persistence mode ?
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(function() {
return firebase.auth().signInWithEmailAndPassword(email, password);
})
Auth session is automatically persistent on the frontend of your app, however Nuxt.js contains frontend and backend part. If you are storing user data somewhere on the frontend, you probably need to wait until the user data become accessible.
Example of the listener:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log('User is logged: ', user);
}
});
However this will make user accessible only on the frontend, if you want to preload data on the backend you would need to store id and refresh token in the cookies or use Nuxt Firebase module which should handle service worker for you.
So, in your case it looks like you are trying to read the data before your user data become accessible (this can be caused by trying to fetch data on the backend).

REST API with Google Firebase Authentication & Functions using Bearer Token

Quick Background: I'm programming an API that is thought to be used "standalone" i.e. there is no frontend involved. API access should be possible directly from e.g. Postman or Curl with a Bearer token in the Authentication Header.
I was looking at Google Firebase and thought it is probably a really good fit because all of the authentication is already "builtin" and directly compatible with Google Cloud Functions.
However after a weekend of experimenting I can not seem to figure out how to implement an REST API (With Google Cloud Functions) where the User can (In an web-interface) request an API token to interact with the API.
I don't want to handle authentication myself. I really would love to use the Firebase authentication for the API.
Here is what the final process should look like:
User logs into an web-interface with the standard Firebase Authentication process.
User clicks on something like "Request API Key" and gets a key shown in the web-interface (e.g. abc...). that is generated by Firebase Authentication.
User can make requests with e.g. curl to the API Hosted in Google Cloud Functions and just has to set the Authorization Header (Bearer abc...) and the "validation" of that token is handled by Firebase Authentication.
Here is what I already tried to generate the token:
admin.auth().createCustomToken(uid)
.then(function(customToken) {
console.log(customToken);
})
.catch(function(error) {
console.log('Error creating custom token:', error);
})
And then set the Token logged to the console in Postman as Bearer Token, and then use the following function to verify the token:
const authenticate = async (req, res, next) => {
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
res.status(403).send('Unauthorized');
return;
}
const idToken = req.headers.authorization.split('Bearer ')[1];
try {
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
req.user = decodedIdToken;
next();
return;
} catch(e) {
console.log(e);
res.status(403).send('Unauthorized');
return;
}
}
Then I get this error
message: 'verifyIdToken() expects an ID token, but was given a custom token. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
I understand that if I would implement an web-interface I could grab the ID token from the devtools (?), but the token is then only valid 1 hour... What I need is a token that is valid "indefinitely" and can be generated and shown to the user.
I think I know that I have to use Custom Tokens somehow but can not figure out how to get them working... (https://firebase.google.com/docs/auth/admin/create-custom-tokens).
Thanks very much in advance everybody!
Best
Rick
You're trying to build an API management solution on top of Firebase and Cloud Functions. Custom tokens and ID tokens are not suitable for this purpose. Custom tokens are only meant to be used as a user authentication credential on end user devices, and ID tokens represent a successful auth response. Both types of tokens expire after an hour.
If you need long-lived, managed API keys, then you will have to implement them yourself. There's nothing built into Firebase that you can use out of the box. I once implemented such a solution as a prototype, where I generated a Firestore document each time a user signed in and requested an API key. Then I used the document ID as the API key, which I could validate in the Cloud Function.
const apiKey = req.headers.authorization.split('Bearer ')[1];
const doc = await admin.firestore().collection('apiKeys').doc(apiKey).get();
if (doc.exists) {
next();
}
I also had to implement some local API key caching to make this work efficiently.
You might be able to avoid some of this work by using a solution like Google Cloud Endpoints (https://cloud.google.com/endpoints), although I don't have any personal experience with that. Finally, also look at open source solutions like https://wso2.com/api-management/ that enable you to set up your own API key management and gateway.

How to prevent Firebase anonymous user token from expiring

I'm using anonymous authentication is a Firebase app. I just noticed that I have over 100 anonymous users now registered even though all I've been doing is testing the app. It looks like the expiration time for the user token is quite short, and as soon as it expires the next login causes a new user to be created.
What is the best way to avoid this? I could presumably refresh the user's token but I'm not sure how to this since in onAuthStateChange the user parameter is null if the user has expired.
Or should I changed the expiration time? If so, how do I do this? I found some instructions for doing so in the old Firebase docs but can't see how to do it in the latest version.
UPDATE: Currently I am initializing the app and authenticating the (anonymous) user like so:
firebase.initializeApp(FIREBASE_CONFIG);
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously().catch(error => {
console.error('Failed to authenticate with Firebase', error);
});
}
});

Categories

Resources