Firebase revoked tokens and authentication - node.js

I am creating an flutter app that uses firebase authentication. I have added a change email option and have some questions regarding the sessions.
Firstly, when the user changes their email the refresh token is revoked. The firebase documentation examples make use of the realtime database to keep track of the times when tokens are revoked. These are then checked in the database rules. The example to update the database can be seen below
const metadataRef = admin.database().ref('metadata/' + uid);
metadataRef.set({revokeTime: utcRevocationTimeSecs})
.then(() => {
console.log('Database updated successfully.');
});
https://firebase.google.com/docs/auth/admin/manage-sessions#detect_id_token_revocation_in_the_sdk
I'm not sure where to call this code when the email address is changed via the client sdk. Is there a email updated firebase function trigger that I am missing where this timestamp can be written?
I thought about just calling a firebase function but what stops this from being commented out before an attacker updates the email.
Thanks.

Related

Node.js: Google Calendar On Behalf of User

I am trying to access multiple users' Google Calendars in a search functionality with Flutter and Firebase Functions in Node.js.
I originally ask for user permission here in the app (Flutter):
clientViaUserConsent(_credentialsID, _scopes, prompt)
.then((AuthClient client) async {
The credentials for the user are then stored locally and in Firestore via a restricted Firebase Function for security reasons.
Calling Firebase Function (Node.js):
FirebaseFunctions.instance
.httpsCallable('addCalendar')
.call(<String, dynamic>{
'calendarAuthToken': client.credentials.accessToken.data,
'calendarRefreshToken': client.credentials.refreshToken!,
'calendarExpiration':
client.credentials.accessToken.expiry.toString(),
'idToken': client.credentials.idToken.toString()
});
Firebase Function:
return await admin.firestore().collection('[example text]').doc('[example text]').set({
CalendarAccessToken: calendarAccessToken,
CalendarRefreshToken: calendarRefreshToken,
CalendarExpiration: calendarExpiration,
// CalendarIDToken: calendarIDToken
}).then(() => {
I have a search functionality which needs access to all users' calendars. Obviously this should never be done locally due to the sensitivity of the data, so I am trying to do this in a Firebase Function as well.
exports.isAvailableNow = functions.https.onCall(async (data, context) => {
const id = data.id;
const cal= await admin.firestore().collection('[example text]').doc(id)
Should I be reconstructing user's credentials in the Firebase Function, or should I instead be using a service account? The reconstruction could get blocked because it is running on Firebase, not locally like the user permitted. If I need to use a service account, how does that change the original authorization in flutter?
EDIT: Changed the title
UPDATE: I managed to reconstruct the authentication for the user on the server-side, but my fear has become a reality. Google is saying I am not authorized for the user. How do I authorize a user on the client then access their data on the backend?

Method Creating custom tokens will create uid if not exist in firebase

I using firebase. I using method: Creating custom tokens. When i look document in firebase https://cloud.google.com/identity-platform/docs/admin/create-custom-tokens .
const uid = 'some-uid';
admin
.auth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
I have a question
If i don't have uid in firebase, it will create it ? If i have uid, i only create custom token and send back to client. I look document and i don't see document specific it. Thanks
There is no need to make an API call to create a user in Firebase when you're using custom authentication. Calling createCustomToken on the server, and then signing on the client with the resulting ID token, is all that is needed.
There is no separate step to create the UID for a custom provider. You create the custom token with the UID and other claims you want, send it to the client over a secure connection, and the client can then sign in to Firebase with that token.
For Firebase services the ID token, and the UID in it, are ephemeral - since it is your server (where you run the Admin SDK), and the client that maintain them. That's the reason a separate step to create the UID in Firebase is not necessary.

firebase.auth().currentUser returning null

In the html file that I have for the sign-in page, I perform the authentication using Firebase and on successful authentication, I redirect the given user to the homepage. When I call firebase.auth().currentUser in the express file, I use for rendering and routing pages, I get undefined or null for the current user.
Can anyone help me understand what the issue might be?
This is how I perform the authentication:
firebase
.auth()
.signInWithEmailAndPassword(temail, tpass)
.then(function(firebaseUser) {
window.location.href = "http://localhost:5000/homepage";
})
.catch(function(error) {
window.alert("incorrect pass");
});
This is the code that I have in my express file:
app.get("/homepage", (req, res) => {
var user = firebase.auth().currentUser;
console.log("USER IS " + user);
res.render("menu", { title: "Welcome" });
});
Backend code doesn't have a sense of "current user". When you sign in on the frontend, the current user is only known on that client. It isn't known on the backend. If you want the backend to know which user is signed in, the client will have to send an ID token to the backend for it to verify. The documentation for the Firebase Admin SDK is used for that on the backend. The client must send the ID token to in the request to your route, and the code handling that route must verify the token in order to know the user that made the request. From the documentation:
If your Firebase client app communicates with a custom backend server, you might need to identify the currently signed-in user on that server. To do so securely, after a successful sign-in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity and authenticity of the ID token and retrieve the uid from it. You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.
When the user lands on a new page, Firebase automatically restores their previous authentication state. But to do so, it may have to contact the server, which means that it may take a few moments. While Firebase is restoring the state, auth().currentUser will be null.
To ensure you get the correct authentication state, you should use an authentication state listener, as shown in the documentation on getting the current user:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});

Firebase Admin Token is being generated with invalid signature

I have created an App using the Parse server, and have now decided to implement some aspects of firebase into my app. Im trying to accomplish this by doing the signInWithCustomToken method in swift on ios. Im calling a rest service to generate a firebase token, and then signing in with that token returned upon valid sign in on my current auth system. However, the token being generated appears to have an invalid signature when pasting it into jwt.io. The environment that im using is node based (inside the parse server). It seems very simple and i have followed the firebase instrucutions/poured over questions on this over the last few days and im really not sure what im doing wrong! Heres my rest service on how i generate the token, i initialize the server with this method:
Parse.Cloud.define("initServer", function(request, response){
var admin = require('firebase-admin');
var serviceAccount = require('/home/bitnami/apps/parse/htdocs/firebase/serviceAccountKey.json');
console.log(serviceAccount);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://urabo-acb7a.firebaseio.com'
});
response.success("Server Init OK");
});
this is the post method i call to generate the token from firebase-admin sdk:
Parse.Cloud.define("generateFirebaseToken", function(request, response) {
var admin = require('firebase-admin');
admin.auth().createCustomToken(request.params.uid)
.then(function(customToken) {
// Send token back to client
response.success(customToken);
})
.catch(function(error) {
console.log("Error creating custom token:", error);
});
});
And of course I went into the firebase console and generated the private key, and then scp'd it over to my server. Im not really sure why this is not working, it generates a token it just doesnt appear to be valid or linked to my account. Am i missing some weird encoding issue or something with the token? Does anyone have insight on this?? Thanks so much!
—The main question is are your users signing in to the REST service through your app and then you are also trying to re-authenticate them again with the token generated in your system?
—If they will be accessing further REST functions once authenticated, then why not authenticate them successfully when 'a' token is returned?
—Usually token usage or handling is restricted by the API providers. Another option is instead of involving user auth directly with the API service, have a separate auth system — the usual SignIn process and then make API calls based on the requested API feature. That way your app is interacting with the APIs and users remain at the front end.

How to destroy an idToken in firebase-admin?

I am trying to stop a nodejs server operation using firebase-admin, I am not using firebase-functions because it doesn't fit my requirements
I have successfully created an idToken and verified it in the server using the firebase code.
admin.auth().verifyIdToken(idToken)
.then(function(decodedToken) {
var uid = decodedToken.uid;
// ...
}).catch(function(error) {
// Handle error
});
The problem is that when I logout on the client the idToken is still live for the remainder of the 60 minutes lifetime.
How do I destroy an IdToken so the server operation stops working?
There is no API to invalidate/revoke an ID token. You will have to implement this unauthorized behavior in some other way. Perhaps you can set a value in Firebase database at logout, and look for it in subsequent calls. For completeness, here are some previous discussions on this topic:
https://groups.google.com/forum/#!topic/firebase-talk/hPNd5-RNgBs
How to revoke an authentication token?

Resources