Maksim Nesterenko
Maksim Nesterenko

Reputation: 6213

How to implement "remember me" feature in feathers.js and JWT

Feathers use JSON web token for auth. How can I conditionally set token's expiresIn property depends on "remember me" was checked or not.

Upvotes: 1

Views: 2527

Answers (2)

Stan Bondi
Stan Bondi

Reputation: 4596

Updated thoughts: this method is a hack (potentially with security implications) - what I think should happen is if you click remember me, you should be issued a refresh token which should be used to issue a new token automatically should it expire or not exist. I'd love to hear what suggestions the feathers devs have - I'm looking into this and will report back if I find a better solution

What might happen with a cookie-based solution is if a user sets remember me, they are issued with a token with an expiry date, otherwise they are issued a session cookie which is removed once the browser session ends (browser is closed). When using a JSON Web Token(JWT) with feathers.authentication (< 1.x ??) we are storing a JSON Web Token (JWT) in a storage provider such as localStorage. If you want your login token to disappear after the browser closes you should use sessionStorage.

My current solution is to use both, depending on my form value when I logged in. In the case the user chooses 'remember me' I'll call storage.setShouldPersist(true) (likewise storage.setShouldPesist(false) if remember me is not checked) which will place a flag in localstorage saying that we are in "localStorage" mode. I pass an object which duck types Storage (getItem, setItem etc.) to feather.authentication which checks if my rememberme key is present. If so, it uses localStorage otherwise it uses sessionsStorage.

Here is the code:

// localOrSessionStore.js
const { localStorage, sessionStorage } = global;

export default function localOrSessionStore({ key }) {
  let shouldPersist = localStorage.getItem(key) === 't';

  return {
    setShouldPersist(persist) {
      shouldPersist = !!persist;
      if (persist) {
        localStorage.setItem(key, 't');
      }  else {
        localStorage.removeItem(key);
      }
    },

    getItem(name) {
      if (shouldPersist) {
        return localStorage.getItem(name);
      }

      return sessionStorage.getItem(name);
    },

    setItem(name, value) {
      if (shouldPersist) {
        return localStorage.setItem(name, value);
      }

      return sessionStorage.setItem(name, value);
    },

    removeItem(name) {
      if (shouldPersist) {
        return localStorage.removeItem(name);
      }

      return sessionStorage.removeItem(name);
    },
  };
}

Then usage:

# feathers.js - where I set up feathers for my app
export const storage = localOrSessionStore({ key: 'myapprmbr' });
export default feathers()
  .configure(rest('/api').fetch(fetch))
  .configure(feathers.hooks())
  .configure(feathers.authentication({
    storage, // Passed into feathers-auth here
    tokenKey: 'myappjwt',
  });

The new feathers-authetication@>=1.x and feathers-authetication-client packages have some changes which I'm not yet familiar with, which may better enable remember me functionality.

Upvotes: 4

Daff
Daff

Reputation: 44215

The way to not remember a JWT is not to store it on the client side. If you are using the Feathers client with authentication the token is stored in localStorage as feathers-jwt. You can "unremember" it for the next browser session by calling

localStorage.removeItem('feathers-jwt')

Upvotes: 1

Related Questions