Firebase admin - get Google OAuth token - firebase

I have a web application where users can sign in with Google.
To the sign-in process, I add a scope to be able to access Google Calendar.
Now that the user is signed in, I would like to - in server-side - get their current Google access token in order to make a request and get a list of their events.
Is there a way to get the current OAuth token (no need for refresh token) in order for me to make this completely on the server-side?

I'd say that you can check this article and put special attention to the recommendation for websites.
I understand you have configured already the consent screen, which is the first step of the basic steps on using OAuth 2.0. So I understand that you only have to perform the following steps:
Obtain an access token from the Google Authorization Server
Examine scopes of access granted by the user.
Send the access token to an API
I think you can also give a look to this other doc for more GCP insights over your goal to authorize the request using user tokens
Edited:
Regarding the Firebase Authentication, I understand this happens at the user's device, and you could use some code to retrieve the token and then send it to your back end servers as mentioned in here.
As a sample here there's the sample code for retrieving the token in Android:
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});

A little about OAuth 2.0
Whenever a user signs up to your app/website via Google or 3rd Party, an Authorization Code, this Authorization Code is exchanged for an AccessToken & RefreshToken.
The AccessToken sent via Google are valid generally for 60 minutes.
Offline Access (Server Side)
Let's break it down to two parts:
If your need to update within 60 minutes of user's last activity
You can use firebase along with gapi to achieve that. You'll be provided with the AccessToken that can be sent back to server to add to calendar.
More info on implementation
If you need to update after 60 minutes of user's last activity
Firebase & gapi's most method handle the AuthorizationCode flow internally. They even further refresh the AccessToken after 60 minutes. This is beneficial for most developers as they won't have a headache of managing all the tokens.
This method but, hides RefreshToken & AuthorizationCode from the developer. That is even if your server has the access token, it won't be able to refresh it and it would be deemed useless.
To achieve complete offline access, in the initial request to get AuthorizationCode you will need to send a HTTP GET parameter access_type to offline
GAPI provides you with grantOfflineAccess() method which returns the AuthorizationCode that can be later used on your server to fetch access token & refresh token.
Note: If you are storing AuthorizationCode in your database, make sure it is secure. The limitation in Firebase are set due to security reason. It is more secure to not talk with AuthorizationCode generally.
More links
https://developers.google.com/identity/protocols/oauth2/web-server
https://developers.google.com/identity/sign-in/web/reference
https://developers.google.com/identity/sign-in/web/server-side-flow
https://developers.google.com/identity/sign-in/web/backend-auth
Retrieve Google Access Token after authenticated using Firebase Authentication

Related

firebase oauth2 accessToken useless

In firebase we can use signInWithPopup and get our auth provider access token by credential.accessToken.
We can only get this accessToken one time after login. But this access token is expired in one hour!
And we need to force user to login again to get access token.
What the point of this completely useless access token user experience? If we cant use it anyway.
update:
I'm developing Chrome Extension with Firebase and trying to add Google Calendar support. And I spent already several days but didn't found solution.
first GAPI is not working in Chrome Extension. I tried to use signInWithPopup and make it with REST calls but google.com oauth2 access token in firebase is expiring after one hour and there is no way to refresh it silently.
This is all Google products and why they are so hard to make work together?
update2:
provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('https://www.googleapis.com/auth/calendar.events');
const result = await firebase.auth().signInWithPopup(provider)
var credential = result.credential;
// Saving **credential** somewhere for later use it in REST calls to` https://www.googleapis.com/calendar/v3/users/me/calendarList
PROBLEM this access token is expired after ONE hour.

Firebase auth idTokens

I have read so many articles about firebase auth on web but couldn't find any clear explanation of how idTokens are supposed to be used on the client side. Here is what I know so far
After the user has logged in, we can get the token using the following method and it will automatically refresh the token if it has expired
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
}).catch(function(error) {
// Handle error
});
We can then send this token to our backend where we can use firebase admin SDK to verify the id token and get the user uid.
admin.auth().verifyIdToken(idToken).then(function(decodedToken) {
var uid = decodedToken.uid;
// ...
}).catch(function(error) {
// Handle error
});
Here are the things which I don't understand.
Do I need to call getIdToken() method before each API call to the server to get the idToken?
Firebase documentation says that the token expires after 1 hour. So am I supposed to keep a track of that using localStorage and then reuse the token for 1 hour till it expires and then issue a new one using getIdToken()?
Should I instead create a session on the backend with the uid which won't expire and then use that to verify if the user has logged in or not?
No; as you noted, the token is valid for an hour. You can reuse the same token during that period unless you have a reason to refresh it (for example, if you add custom claims)
Ideally your server will return a 401 Unauthorized or something when the token is invalid. Most REST libraries provide the ability to add interceptors in the request chain, so you can check if you get back a 401 code and only refresh the token when necessary.
There is no need for a backend session unless your business logic requires it. The Firebase library will handle persistence for you.

How to sync firebase users across several locations? (extension + website)

I'm working on chrome extension (provides main functionality) and the complementary website (mostly profile and billing related functionality) both backed with firebase backend.
I'm wondering if it's possible to implement the below scenario:
user logs in with the extension using firebase authentication (with firebaseUI lib)
I store a token that I can use to reauthenticate that user (is there such a token?)
when user opens the website, I login that user automatically with the token.
While both the extension and the website has their login/signup forms I'm wondering if it's possible to login user in the extension and to somehow automatically login that same user on the website so they don't have to enter their credentials twice?
So far I was hoping that I could use something like below:
firebase.auth().currentUser.getIdToken(true).then(function(idToken) {
console.log("idToken = ", idToken)
})
And then to use that idToken like this, since if I understand correctly, it's an AWT:
firebase.auth().signInWithCustomToken(idToken).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log("signInWithCustomToken: error = ", error)
})
But it gives the following error:
code: "auth/invalid-custom-token"
message: "The custom token format is incorrect. Please check the documentation."
I can parse the token on https://jwt.io/ which shows all the user information but in the end it says "invalid signature"
So I guess this token can be only used to check authentication (like admin.auth().verifyIdToken(idToken)) but not to login user. Am I right?
I know I can create a custom token, but is there any straightforward way to workaround that and to login user from one place only using firebase funstionality? (of course without storing username/password)
You can't sign in with a Firebase ID token. What you can do is the following:
Keep the user session in the chrome extension and run all authenticated requests from there. Use postMessage (with origin verification) to talk with extension from app anytime a request is to be sent. With this you don't have to worry about session synchronization and no Firebase tokens are stored or passed to the web app or every web app that can access the extension.
Add a postMessage API to get an ID token from the extension after verifying the origin of the request. You can then send the request from the web app with the ID token. (less secure than 1 but easier to implement and session is stored in one place).
Create an HTTP endpoint that takes an ID token and returns a custom token. This would verifyIdToken and then create a corresponding custom token for that user using createCustomToken provided by Admin SDK. You then postMessage that from chrome extension to the web page after verifying origin and signInWithCustomToken with that custom token in that web app. This is the least secure as you are providing an endpoint to exchange a short lived ID token with an indefinite session. You will also deal with synchronization issues (user signs out from chrome extension, you have to sign out from websites, etc).

Using firebase jwt to authenticate users to external server\service?

Okay so in my iOS app I log the user into firebase, then get the jwt token. So now I have my server with an api which accepts an idtoken in the header of the GET.
What do I do here? Certainly I wouldn't be validating the JWT againt firebase on every single API call right? I mean its fast, but that adds latency with a second external check, no? How does one simply just decode that guy in C#? I have an Auth0 layer already and that decodes the JWT with my server-stored secret, but that same code doesn't work for the Firebase token.
Could it just be decoded then extract the user details from that, maybe just check expiry and if expiry > X months it's still okay?
In order to verify Firebase ID tokens and JWTs in general, you only make a network call on your server to get the public certs which are usually not updated for several hours. You could cache that and try to verify with an ID token and if it fails, only then, load the new public certs.
And yes, you must verify the ID token on each call especially since Firebase ID tokens expire after typically an hour and need to be refreshed continuously.

Firebase signInWithCustomToken handle token expiry

I'm using firebase 9.x with custom authentication. According to the documentation the token expiry cannot be more than one hour. Is there a listener which I can register to that will be called when the token expires.
The documentation also talks about automatic refreshing of tokens. I believe that is not applicable for custom authentication. Let me know otherwise.
https://firebase.google.com/docs/auth/server#use_the_firebase_server_sdk
Ideally the documentation (above) should have the requested information.
Thanks in advance.
The token that is generated server side (custom auth) is a JWT (JSON Web Token). This token must be supplied by your client (Android?) to the Firebase server to authenticate the user to Firebase. In the 9.x libraries, it seems these tokens now have a maximum life of an hour (i.e they are no longer accepted after 60 mins). (See Sam Stern's comment in this issue: https://github.com/firebase/quickstart-android/issues/31).
Sam indicates that once authentication has occurred using a custom generated token, the Android client will remain authorised until signed out.
If you actually require to know when your JWT token is valid until, it should be 60 minutes after you generate it on your server. If the token has not yet been used for auth with Firebase, at this point you could regenerate a new one and use that instead.
The documentation is misleading. It should say you have 1 hour to use the custom token to sign in. I also feel if the token is that temporary, then it should be single use. Otherwise it is confusing how they want you to use the token.
The SDK will take care of keeping the sessions tokens up to date IF YOU ARE SETUP correctly. For more info The custom tokens are only used to start a SESSION. So you have to have hour to use a custom token to SIGN IN. Once you are signed in and your Firebase Admin account and app configuration is setup correctly, the SDK can communicate back and forth with the Firebase back-end to keep the tokens up to date. Once you sign out with FirebaseAuth.signout(), you will need a new custom token to sign back in if it has been over 1 hour.
So in most cases, you really do not need to listen for token expiration
have you tried AuthListener?
mAuthListener = new FirebaseAuth.AuthStateListener(){
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
user.getCurrentUser().getToken(true);
// ...
}
};;
mAuth.addAuthStateListener(mAuthListener);

Resources