95

I use the JS library call firebase.auth().signInWithEmailAndPassword(email, password) and get back a User object. The User object contains a refreshToken.

I use curl 'https://docs-examples.firebaseio.com/rest/saving-data/auth-example.json?auth=TOKEN' to make calls to Firebase.

The token will eventually expire. In order to make it look like the application (iOS and macOS) has persistent login, I want to refresh the token, how do I do that with using either the REST or JS library? I can't find any calls in the documentation that allow me to use the refreshToken to get a new token.

4 Answers 4

75

When you make call from a browser .getIdToken(true) will automatically refresh your token. Make call like this:

Namespaced / compat API (v8)

firebase.auth().currentUser.getIdToken(/ forceRefresh / true)
  .then(function(idToken) {
    
  }).catch(function(error) {

});

More info https://firebase.google.com/docs/reference/js/v8/firebase.User#getidtoken

Modular API (v9+)

import {getAuth} from 'firebase/auth'
auth = getAuth()

auth.currentUser.getIdToken(/ forceRefresh / true)
  .then(function(idToken) {
    
  }).catch(function(error) {

});

More info https://firebase.google.com/docs/reference/js/auth.user.md#usergetidtoken

9
  • 14
    Wouldn't currentUser be NULL on a fresh launch of an app? I don't know how it is on a regular browser, but I do not store any cookies or local data. I only store the refreshToken and anything else that I specifically need.
    – kgaidis
    Jul 6, 2016 at 21:13
  • 2
    Login is needed to be performed first to use that code. If you use sign in with firebase it should work.
    – Yevgen
    Jul 7, 2016 at 5:52
  • 3
    This! But .getToken is deprecated now, you must use .getIdToken. Jul 12, 2017 at 4:20
  • 2
    @TakamitsuMizutori I had the same issue, the token couldn't be refreshed. I solved it by enabling the Token Service API for my Google API key. Apr 18, 2020 at 16:33
  • 1
    @Gunee My apologies, but I now think my previous comment (which I will delete) was wrong: getIdToken() always returns a valid token. This is based on my personal experience using that function in a React Native app. (Thank you for calling my attention to my incorrect comment.)
    – stevehs17
    Jul 6, 2022 at 3:59
64

** UPDATE ** this is also now documented in Firebase REST docs under Exchange a refresh token for an ID token section:

https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token


Currently the only way I found to do this is here: https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token

You must make an HTTP request:

POST https://securetoken.googleapis.com/v1/token?key=YOUR_KEY

Where YOUR_KEY can be found in the Google developers console > API Manager > Credentials. It's under the API Keys section.

Make sure request body is structured in the following format:

grant_type=refresh_token&refresh_token=REFRESH_TOKEN

Where REFRESH_TOKEN is the refresh token from Firebase user object when they signed in.

You must set the header Content-Type: application/json or you will get errors (e.g. "MISSING_GRANT_TYPE").

The POST call will return a new idToken (used to be called access_token)

11
  • Should this request work for refreshing Gmail API's token? @kgaidis
    – ArtStyle
    Aug 27, 2016 at 0:46
  • 1
    I got 403 (Permission denied) error when I do this. Can I call this API from web client javascript ? Mar 13, 2020 at 8:50
  • 2
    access_token = id_token
    – Rakka Rage
    May 30, 2020 at 15:48
  • 1
    thanks so much you made my day, I wish I could have voted a 100 times. My app kept on yelling token expired throughout development, till you came to my aid Nov 12, 2020 at 18:14
  • 2
    For me, it did not work with Content-type: application/json and I had to go back to the old x-www-form-urlencoded.
    – Spoutnik16
    Apr 20, 2022 at 7:05
17

I guess most people here are looking for a way to persist their authentication not in a browser but e.g. on a node backend. Turns out there actually is a way to do this:

  1. Trade the refresh-token for an access-token (using google's public api)
  2. Trade the access-token for a custom-token (using a firebase-function, see below)
  3. Login with custom-token

Here's the essence of the code:

const requestP = require('request-promise');
const fsP = require('fs').promises;

const refreshToken = await fsP.readFile('./refresh_token.txt');
const res = await requestP.post({
  headers: {'content-type': 'application/x-www-form-urlencoded'},
  url: 'https://securetoken.googleapis.com/v1/token?key=' + firebaseConf.apiKey,
  body: 'grant_type=refresh_token&refresh_token=' + refreshToken,
  json: true
});
const customToken = await requestP.post({
  headers: {'content-type': 'text/plain'},
  url: 'https://<yourFirebaseApp>.cloudfunctions.net/createCustomToken',
  body: {token: res.access_token},
  json: true
});
await firebaseApp.auth().signInWithCustomToken(customToken);

And the firebase function:

export const createCustomToken = functions.https.onRequest(async (request, response) => {
  response.set('Access-Control-Allow-Origin', '*');

  try {
      const token = JSON.parse(request.body).token;
      const decodedToken = await admin.auth().verifyIdToken(token);
      const customToken = await admin.auth().createCustomToken(decodedToken.uid);
      response.send(customToken);
  } catch(e) {
      console.log(e);
      response.sendStatus(500);
  }
});
6
  • In my case the custom token expires after one hour, what did you do to solve that? Aug 4, 2019 at 17:44
  • I just read your answer again, I guess what I need to persist is the refresh token and not the custom token. You are continuously creating custom tokens. Aug 5, 2019 at 15:20
  • Yes, you should store the refresh-token, like: firebaseApp.auth().onAuthStateChanged((user) => { if(user) { fs.writeFileSync('./refresh_token.txt', refreshToken); } }); Aug 5, 2019 at 15:47
  • 2
    but the refresh token changes from one user to the other, how do you save it in a text file?
    – Ayyash
    Aug 28, 2019 at 5:30
  • is this safe to the public to create custom tokens from refresh tokens?
    – Michael Xu
    Mar 17, 2021 at 20:59
2
// Create a callback which logs the current auth state
function authDataCallback(authData) {
  if (authData) {
    console.log("User " + authData['uid'] + " is logged with token" + authData['ie']);
  } else {
    console.log("User is logged out");
  }
}
// Register the callback to be fired every time auth state changes
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.onAuth(authDataCallback);

Event onAuth will be called on page refresh, if user was logged out authData will be null, else not. You can find token in authdata['ie']. In the screenshot bellow I have printed the token after auth and authdata object, how you can see authData['ie'] and token are similar.

authdata.ie and token

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.