Skip to content
Advertisement

How to prevent simultaneous logins of the same user with Firebase?

I’d like for the new session to essentially “log out” of any previous session. For example, when you are in an authenticated session in one computer, starting a new session on another computer and authenticating with firebase on our app will log out the other session on the first computer.

I haven’t been able to find any method that allows me to log out of a session “remotely”. I know that I can unauth() and goOffline() from within a session. But how do I do it from a different authenticated session of the same user?

Thanks for the help!

Background Info:

  1. I am using simple email/password login for firebase authentication
  2. I don’t have security rules setup yet, although this is in the works
  3. I’m using Javascript with Firebase

Advertisement

Answer

The general idea is that you want to create some meta data in Firebase which tells you how many locations a user is logged in from. Then you can restrict their access using this information.

To do this, you’ll need to generate your own tokens (so that the information is available to your security rules).

1) Generate a token

Use custom login to generate your own tokens. Each token should contain a unique ID for the client (IP Address? UUID?)

var FirebaseTokenGenerator = require("firebase-token-generator");
var tokenGenerator = new FirebaseTokenGenerator(YOUR_FIREBASE_SECRET);
var token = tokenGenerator.createToken({ id: USER_ID, location_id: IP_ADDRESS });

2) Use presence to store the user’s location_id

Check out the managing presence primer for details:

var fb = new Firebase(URL);

// after getting auth token back from your server
var parts = deconstructJWT(token);
var ref = fb.child('logged_in_users/'+token.id);

// store the user's location id
ref.set(token.location_id);

// remove location id when user logs out
ref.onDisconnect().remove();

// Helper function to extract claims from a JWT. Does *not* verify the
// validity of the token.
// credits: https://github.com/firebase/angularFire/blob/e8c1d33f34ee5461c0bcd01fc316bcf0649deec6/angularfire.js
function deconstructJWT(token) {
  var segments = token.split(".");
  if (!segments instanceof Array || segments.length !== 3) {
    throw new Error("Invalid JWT");
  }
  var claims = segments[1];
  if (window.atob) {
    return JSON.parse(decodeURIComponent(escape(window.atob(claims))));
  }
  return token;
}

3) Add security rules

In security rules, enforce that only the current unique location may read data

{
  "some_restricted_path": {
     ".read": "root.child('logged_in_users/'+auth.id).val() === auth.location_id"
  }
}

4) Control write access to logged_in_users

You’ll want to set up some system of controlling write access to logged_in_users. Obviously a user should only be able to write to their own record. If you want the first login attempt to always win, then prevent write if a value exists (until they log out) by using ".write": "!data.exists()"

However, you can greatly simplify by allowing the last login to win, in which case it overwrites the old location value and the previous logins will be invalidated and fail to read.

5) This is not a solution to control the number of concurrents

You can’t use this to prevent multiple concurrents to your Firebase. See goOffline() and goOnline() for more data on accomplishing this (or get a paid plan so you have no hard cap on connections).

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement