Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase admin sdk: idToken OR custom token verification for authorization

I'm creating a custom token on backend server while login and below is the code:

UserSchema.methods.generateAuthToken = function() {
 var user = this;
 var access = "auth";

 return firebaseAdmin.default
  .auth()
  .createCustomToken(user._id.toHexString())
  .then(function(token) {
    user.tokens = user.tokens.concat([{ access, token }]);
    return user.save().then(() => {
      return token;
    });
  });
};

and storing this token inside mongodb and sending it back to client via header named "x-auth" and then stored it inside cookies.

On client side, using this token to signin like below:

axios({
  url: "/api/users/login",
  method: "POST",
  data: {
    email: data.email,
    password: data.password
  }
}).then(res => {
  Cookies.set("x-auth", res.headers["x-auth"], { expires: 7 });
  return firebase
    .auth()
    .signInWithCustomToken(res.headers["x-auth"])
    .then(response => {
      console.log("CA", response);
      response
        .getIdToken()
        .then(idToken => {
          Cookies.set("idToken", idToken, { expires: 7 });
        })
        .catch(e => {});
      dispatch(
        login({
          token: Cookies.get("x-auth")
        })
      );
    });
});

Now in order to call an api to fetch all users, I'm sending these tokens, custom token and idToken back to server:

const authenticate = (req, res, next) => {
const token = req.header("x-auth");
const idToken = req.header("idToken");
User.findByToken(token, idToken)
.then(user => {
  if (!user) {
    return Promise.reject({
      message: "no user found with the associated token!"
    });
  }
  req.user = user;
  req.token = token;
  next();
})
.catch(e => {
  res.status(401).send(setErrorMessage(e.message));
});
};

And findByToken is as below:

UserSchema.statics.findByToken = function(token, idToken) {
var User = this;
return firebaseAdmin.default
.auth()
.verifyIdToken(idToken)
.then(function(decodedToken) {
  var uid = decodedToken.uid;
  return User.findOne({
    _id: uid,
    "tokens.access": "auth",
    "tokens.token": token
  });
})
.catch(function(e) {
  return Promise.reject(e);
});
};

Why do I have to send both these tokens for authorization, is there anything wrong with the concept here.

https://firebase.google.com/docs/auth/admin/verify-id-tokens

Warning: The ID token verification methods included in the Firebase Admin SDKs are meant to verify ID tokens that come from the client SDKs, not the custom tokens that you create with the Admin SDKs. See Auth tokens for more information.

Please clarify if I can verify the custom token instead of idToken to retrieve userId and match it up with DB, instead of using different tokens for one purpose or I'm doing something wrong here and custom token should not be stored inside DB, and there is some other approach to it.

And now after sometime when I try to fetch all users, it says:

Firebase ID token has expired. Get a fresh token from your client app and try again (auth/id-token-expired). See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.

like image 331
Vipul Avatar asked Apr 21 '18 14:04

Vipul


People also ask

How to Verify ID token Firebase?

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.

How do I get OAuth 2.0 access token for Firebase?

Once you have a service account key file, you can use one of the Google API client libraries to generate a Google OAuth2 access token with the following required scopes: https://www.googleapis.com/auth/userinfo.email. https://www.googleapis.com/auth/firebase.database.

How do I verify a token?

There are two ways to verify a token: locally or remotely with Okta. The token is signed with a JSON Web Key (JWK) using the RS256 algorithm. To validate the signature, Okta provides your application with a public key that can be used.

How do I get the JWT token from Firebase Authentication?

To achieve this, you must create a server endpoint that accepts sign-in credentials—such as a username and password—and, if the credentials are valid, returns a custom JWT. The custom JWT returned from your server can then be used by a client device to authenticate with Firebase (iOS+, Android, web).


1 Answers

When working with tokens, you need to differentiate each token and what it is used for, also each token has related properties.

Custom Tokens: These tokens will be generated in the server (as you are doing) and are used in the client side to authenticate the client. These tokens expire after one hour.

Session ID Token: (I'm calling it "Session ID Token" just to differentiate it) When the client autheticates with any of the authentication providers, the SDK will exchange the information for an ID token used for the session. The same applies for custom tokens, where the SDK exchanges the custom token for an ID Token. ID Tokens are also short live and will expire after one hour. When getting the ID Token, the SDK also receives a refresh Token which is used for refreshing the session ID Token. The ID token is used when doing authenticated requests to Firebase.

ID Token for verification: To get this token, you will need to call the function "getIDToken" (for Web). This function will return an ID Token that can be used only to verify requests coming from the client to your server. Similar to the other tokens, this one expires after one hour. When calling the getIDToken, the function will request a new one if the current is expired.

To verify the ID Token, you must use the mentioned token. If you try to use the session ID Token or the Custom token, you will get errors. The same applies if you try to use an expired ID Token.

All the calls and tasks to refresh the ID Tokens are handled by the SDKs behind the scenes.

It is not a good practice to store these tokens as they will expire after one hour, is better if you call the appropriate functions to get the latets tokens and pass the correct ID Token to be verified.

Lastly, you can find in these links the properties used for generating the custom token and the ID Token for verification.

like image 120
Gerardo Avatar answered Oct 17 '22 03:10

Gerardo