Get Google access token - firebase

To get Google access token after firebase auth login, I know I can simply do this:
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
}
but what if the user is already authenticated and I need the token? is there any way to extract it from the Firebase auth?
I've been through every value of authState but I couldn't find the google access token I've been looking for.

You can't get the access token from the onAuthStateChanged listener or the currentUser. You can only get it immediately after authentication when calling signInWithPopup, reauthenticateWithPopup, linkWithPopup, getRedirectResult, etc. Firebase Auth does not manage OAuth tokens for users. If you feel strongly about this feature, please file a feature request for it on the Firebase forum: https://groups.google.com/forum/#!forum/firebase-talk
You can also just use the GApi library to get the Google access token and pass it to Firebase to sign-in via signInWithCredential. The advantage here is that GApi will manage that OAuth token for you.

Related

Incremental authorization with Firebase and GoogleAuthProvider

I'm using Firebase v8 with the GoogleAuthProvider.
Firebase documentation provides the following code to authenticate the user.
firebase.auth().signInWithPopup(provider).then((result) => {
/** #type {firebase.auth.OAuthCredential} */
var credential = result.credential;
// This gives you a Google Access Token. You can use it to access the Google API.
var token = credential.accessToken;
// The signed-in user info.
var user = result.user;
// ...
})
Questions
Google's Using OAuth 2.0 to Access Google APIs article recommends incremental authorization (it's not Firebase, but the recommendation is clear)
It is generally a best practice to request scopes incrementally, at
the time access is required, rather than up front. For example, an app
that wants to support saving an event to a calendar should not request
Google Calendar access until the user presses the "Add to Calendar"
button.
AFAICT, there is no way to achieve incremental authorization with Firebase without re-authenticating the user. While scopes can be added to GoogleAuthProvider using addScope, a subsequent call to signInWithPopup is required (i.e. the user is re-authenticated). Is there any way to prompt only for authorization (e.g. Drive access) without re-authenticating?
Assuming the access token is short lived, can the Google ID token be used to obtain a new access token? Is re-authenticating the user the only way to obtain a new access token?
Is there a way to determine whether the access token has expired?

Is it possible to get accessToken on behalf of user's RefreshToken?

In my web application I have integrated user Firebase Authentication using Google Sign-in. After successful sign-in Firebase returns AccessToken and RefreshToken. Using this AccessToken I am able to call Google APIs (eg; calendar API).
What I wanted to know: If I store user's RefreshToken in DB, later on (may be after a week or so) application backend can get user's RefreshToken from DB and call some Google API (don't know which and how) to retrieve user's AccessToken. This AccessToken will be used to call Google APIs without any issue.
In short, is it possible for backend to retrieve user's AccessToken by using user's RefreshToken for calling Google APIs?
I cant say i have tried with something that came from firebase auth but in theory it should work
This is the call you make.
HTTP POST https://accounts.google.com/o/oauth2/token
client_id={ClientId}&client_secret={ClientSecret}&refresh_token=[REFRESHTOKEN]&grant_type=refresh_token
Love to hear if it works or not.

Sign out user via REST HTTP API

I can sign in users to Firebase using this HTTP API:
How do I sign out users, so that the Firebase idToken and refreshToken can no longer be used?
Also, how long is the refreshToken valid for?
If my user does not use my app for weeks, can I still use the refreshToken or will I need to get a fresh Google Sign In idToken and exchange it for a Firebase (idToken, refreshToken) pair via the /identitytoolkit/v3/relyingparty/verifyAssertion API?
I don't believe there is a sign out endpoint. You could try doing a redirect to https://accounts.google.com/Logout but I suspect that is signing out from all Google services which might not be a great idea.
The whole point of Refresh Tokens is that they can be used to access resources whether or not the user is present and signed in, so your comment "How do I sign out users, so that the Firebase idToken and refreshToken can no longer be used" is an oxymoron.
A Refresh Token is theoretically valid until a user specifically revokes it, but your app should code for the possibility that Google has expired it.
The client cannot directly revoke the ID token via the REST API, but both the Firebase Auth client SDKs (ex: Android) and the Auth Admin SDK do support it. So if your client platform isn't supported, but you are able to create a small server implementation (maybe through Firebase/Cloud Functions), you can create an HTTP endpoint that triggers ID token revocation.

Trouble using Firebase Auth to access google API via gapi SDK

In my firebase (Angular) app, I'm using firebase authentication to log a user in via their Google Profile. As part of this process, the user gives me permission to access their gmail account (scope 'https://www.googleapis.com/auth/gmail.compose').
After the user has logged in this way, I want to configure the "gapi" google javascript SDK so that the "signed in user" is the user signed in via firebase auth. Here's where I'm having trouble.
It appears that I need to set the client token for the gapi sdk like so gapi.client.setToken(userAccessToken) and the token needs to be set before the gapi client is initialized. Attempting to do this doesn't seem to work however (a call to gapi.auth2.getAuthInstance().isSignedIn.get() returns false when it should return true).
I also can't figure out a way of changing the "signed in user" if the firebase user logs out and a new one logs in. This is because, again, the gapi client seems to require the gapi.client.setToken() be called before the client is initialized, and I can't see any way of re-initializing and already initialized gapi client.
I can get the gapi client working if I use the gapi client's own gapi.auth2.getAuthInstance().signIn() method, but then the user is asked to sign in to my app twice using (from the user's perspective) identical google login popup boxes (one prompt originating from firebase auth and the other from the gapi client).
Does anyone have any suggestions / tips? After someone logs in via firebase auth I can get access to their userAccessToken, I just can't figure out how to programmatically pass that to the gapi client in a clean way.
Ideally:
on application load the gapi client would also load and initialize.
When a user chose to sign in, I would be able to use Firebase Auth to log someone in via their google profile, then get their access token and pass it to the gapi client to make google api calls.
If the firebase user ever logged out, I would clear the gapi client's api token.
If a new firebase user logged in, I would re-set the gapi client's api token.
I have come upon a placeholder (i.e. non-ideal) solution to this problem by following this S.O. answer.
In short, the GAPI client does not seem to let you manually pass it an access token, but the firebase auth client does let you manually pass it an access token. So, instead of handling authentication with the firebase sdk and passing the token to the GAPI client, you need to do the reverse and handle authentication with the GAPI client and then pass the token to the firebase SDK.

What format is the Google Picker API auth token?

If I intercept an access_token from an example on this page:
https://developers.google.com/picker/docs/
...it looks like this:
ya29.Glx7BW_OsFJ1CSjJ_kdt9iZixJAZHjvllMtJO09EccpURJPbCXudNP6teBz6HZ0T_ioaQLNna323UPpBQN-N0aCLWXfDVCvq4xXkbi5kKQhfwS0xakcsrNmzD5B8OA
If I paste that into here:
https://jwt.io/
...I'm told it's malformed. However, if I paste a Firebase auth token into there, it's well-formed and you can see its payload.
Ultimately, I'm trying to use the Firebase auth token in the Google Picker API, but I can't figure out how to translate it.
I was using firebase.auth().currentUser.getIdToken, but it looks like firebase.auth().getRedirectResult() gets an auth token that is the same format as the Picker API.
Google API access is scope based https://developers.google.com/identity/protocols/googlescopes
You must specify the scopes needed when requesting an access token.
Each access token you receive back, is limited to the scope and application from its original request. They are not inter-changeable.
You will need to setup a specific Google Picker API request, in order to get the access token you require https://developers.google.com/identity/protocols/OAuth2
Hope this helps
"ya29.*" token is Google's access token and it is not a jwt (it is opaque for the api callers).
Yes firebase allows you to add scopes during the sign-in process. After that you get an id token that says who the user is and a separate access token that you can use to access Google APIs.
If you look at https://firebase.google.com/docs/auth/web/google-signin you will see this:
Then, you can also retrieve the Google provider's OAuth token by calling getRedirectResult when your page loads:
firebase.auth().getRedirectResult().then(function(result) {
if (result.credential) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// ...
}
// The signed-in user info.
var user = result.user;

Resources