Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I add an expiry date to a customToken with Firebase v3?

Tags:

I am in the process of migrating a node.js application to Firebase v3.

In v2 I was using FirebaseTokenGenerator to generate custom tokens. It requires an apiToken, which is inconsistent with the way that Firebase v3 works in node, and I see there is now a 'createCustomToken' method on the firebase.auth service so I am assuming that I should now use that.

The issue is that this method appears to accept only 'uid' and 'developerClaims' as parameters, where FirebaseTokenGenerator also accepted an options object which included an 'expires' attribute.

Is there a way to give the token generated by 'createCustomToken' an expiry date?

like image 718
kpg Avatar asked Jun 01 '16 09:06

kpg


1 Answers

Update

Reference: https://groups.google.com/forum/#!topic/firebase-talk/Ezy3RDNNRAs

Once they login using the custom token, the Firebase exchanged Id token is long lived and is automatically refreshed. You don't need to mint a new custom token on each request. You can verify the Firebase Id token using the backend server libraries and as long as it is valid, you don't to sign in the user again.

So it looks like the generated token is temporary and used to retrieve an id token (internally) with

FIRAuth.auth()?.signInWithCustomToken(customToken)

From then on the client should be good.

With Firebase 3.0.4 Currently No.

From the nodejs module source code it looks like the jwt expiresIn is set at 1 hour. This is unacceptable for mobile app users (as long as they're logged in their key should be fine). Hope this is fixed asap since it blocks us from upgrading our sdk

FirebaseTokenGenerator.prototype.createCustomToken = function(uid, developerClaims) {
  if (typeof uid !== 'string' || uid === '') {
    throw new Error('First argument to createCustomToken() must be a non-empty string uid');
  } else if (uid.length > 128) {
    throw new Error('First argument to createCustomToken() must a uid with less than or equal to 128 characters');
  } else if (typeof developerClaims !== 'undefined' && (typeof developerClaims !== 'object' || developerClaims === null || developerClaims instanceof Array)) {
    throw new Error('Optional second argument to createCustomToken() must be an object containing the developer claims');
  }

  var jwtPayload = {};

  if (typeof developerClaims !== 'undefined') {
    jwtPayload.claims = {};

    for (var key in developerClaims) {
      /* istanbul ignore else */
      if (developerClaims.hasOwnProperty(key)) {
        if (BLACKLISTED_CLAIMS.indexOf(key) !== -1) {
          throw new Error('Developer claim "' + key + '" is reserved and cannot be specified');
        }

        jwtPayload.claims[key] = developerClaims[key];
      }
    }
  }
  jwtPayload.uid = uid;

  return jwt.sign(jwtPayload, this.serviceAccount.private_key, {
    audience: FIREBASE_AUDIENCE,
    expiresIn: ONE_HOUR_IN_SECONDS,
    issuer: this.serviceAccount.client_email,
    subject: this.serviceAccount.client_email,
    algorithm: ALGORITHM
  });
};

Update the below won't work due to this comment "exp The time, in seconds, at which the token expires. It can be at a maximum 3600 seconds later than iat." Firebase token max life span is 1 hour.

The solution appears to be generating our own token

Use a JWT library

You can create a custom token suitable for authenticating with Firebase by using any JWT creation library. Create a JWT that includes the following claims and is signed using RS256.

JWT claims
iss Your project's service account email address
sub Your project's service account email address
aud https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit
iat The current time, in seconds
exp The time, in seconds, at which the token expires. It can be at a maximum 3600 seconds later than iat.
uid The unique identifier of the signed-in user (must be a string, between 1-36 characters long)
claims (optional)   Custom claims to include in the Security Rules auth variable.

An example of a token generating function that should meet the above criteria:

var ALGORITHM = 'RS256';

// List of blacklisted claims which cannot be provided when creating a custom token
var BLACKLISTED_CLAIMS = [
  'acr', 'amr', 'at_hash', 'aud', 'auth_time', 'azp', 'cnf', 'c_hash', 'exp', 'iat', 'iss', 'jti',
  'nbf', 'nonce'
];
var FIREBASE_AUDIENCE = 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit';

function generateFirebaseToken(serviceAccount, uid, expiresIn, developerClaims) {
  var jwtPayload = {};

  if (typeof developerClaims !== 'undefined') {
    jwtPayload.claims = {};

    for (var key in developerClaims) {
      if (developerClaims.hasOwnProperty(key)) {
        if (BLACKLISTED_CLAIMS.indexOf(key) !== -1) {
          throw new Error('Developer claim "' + key + '" is reserved and cannot be specified');
        }

        jwtPayload.claims[key] = developerClaims[key];
      }
    }
  }
  jwtPayload.uid = uid;

  return jwt.sign(jwtPayload, serviceAccount.private_key, {
    audience: FIREBASE_AUDIENCE,
    expiresIn: expiresIn,
    issuer: serviceAccount.client_email,
    subject: serviceAccount.client_email,
    algorithm: ALGORITHM
  });
}

Reference: firebase docs

like image 143
Mark Essel Avatar answered Oct 27 '22 00:10

Mark Essel