Giter VIP home page Giter VIP logo

redux-react-session's Introduction

Redux React Session

NPM version Build status: Linux Dependency Status Coverage Status

Keep your session sync with your local storage and Redux 🔑

Redux React Session provides an API that allows to manage sessions through the app, with authorization function for react-router and a persisted session.

Installation

yarn:

yarn add redux-react-session

npm:

npm install redux-react-session --save

Usage

  • Add the session reducer:
import { combineReducers } from 'redux';
import { sessionReducer } from 'redux-react-session';

const reducers = {
  // ... your other reducers here ...
  session: sessionReducer
};
const reducer = combineReducers(reducers);
  • Initiate the session service:
import { createStore } from 'redux';
import { sessionService } from 'redux-react-session';

const store = createStore(reducer)

sessionService.initSessionService(store);

Examples

The examples simulates a simple login/logout that sends requests to a server.

Run the example for react router v3

  1. get into the folder:cd examples/example
  2. install dependencies: npm install
  3. run the example: npm start

Run the example for react router v4

  1. get into the folder:cd examples/react-router-v4-example
  2. install dependencies: npm install
  3. run the example: npm start

API

initSessionService(store, options) : Promise

Initialize an instance of the session service.

The promise will be resolved if the session is valid, and will be rejected if there is no data in the storage.

Once the promise is resolved or rejected the flag checked in the redux store will change from false to true. This allows to check into any component if the session was already checked and it's valid.

Options:

  • refreshOnCheckAuth(default: false): Refresh Redux store in the checkAuth function
  • redirectPath(default: "login"): Path used when a session is rejected or doesn't exist
  • driver: Force to use a particular driver, could be: 'INDEXEDDB', 'WEBSQL', 'LOCALSTORAGE' or 'COOKIES'
  • validateSession: Function to validate the saved session. It can either be a function to return an immediate boolean value or a function that returns a promise. In the case it returns an immadiate value and false is returned the session will be destroyed. In the case of a promise, if either false is returned or an exception is thrown, the session will be destroyed. Example:
const validateSession = (session) => {
  // check if your session is still valid
  return true;
}
const options = { refreshOnCheckAuth: true, redirectPath: '/home', driver: 'COOKIES', validateSession };

sessionService.initSessionService(store, options)
  .then(() => console.log('Redux React Session is ready and a session was refreshed from your storage'))
  .catch(() => console.log('Redux React Session is ready and there is no session in your storage'));
const validateSession = (session) => {
  // check if your session is still valid with a server check, through axios for instance
  return api.invokeRemoteSessionValidationThroughAxios(session).then(response => response.isSessionValid);
}
const options = { refreshOnCheckAuth: true, redirectPath: '/home', driver: 'COOKIES', validateSession };

sessionService.initSessionService(store, options)
  .then(() => console.log('Redux React Session is ready and a session was refreshed from your storage'))
  .catch(() => console.log('Redux React Session is ready and there is no session in your storage'));

refreshFromLocalStorage

Force to refresh the Redux Store from the local storage.

The promise will be resolved if the session is valid, and will be rejected if there is no data in the storage.

Note: this function is called once the session service is initialized

checkAuth

Authorization function for react-router to restrict routes, it checks if exist a session and redirects to the redirectPath

Example:

import React from 'react';
import { Route, IndexRoute } from 'react-router';
import { sessionService } from 'redux-react-session';
import App from './components/App';
import HomePage from './containers/HomePage';
import LoginPage from './containers/LoginPage';

export default (
  <Route path="/" component={App}>
    <IndexRoute onEnter={sessionService.checkAuth} component={HomePage} />
    <Route path="login" component={LoginPage} />
  </Route>
);

Note: If you're using react-router v4 this function it's not necessary. Check out the react-router-v4-example

Note: This function could be used in the client side as well as the server side.

saveSession(session:object) : Promise

Saves the session object in the storage/cookies and changes the authenticated flag to true in Redux Store

loadSession : Promise(currentSession:Object)

Returns the current session if exists

Example:

loadSession
.then(currentSession => console.log(currentSession))
.catch(err => console.log(err))

deleteSession : Promise

Deletes the current session from the storage/cookies

saveUser(user:object) : Promise

Saves the user object in the storage/cookies and in the Redux Store

loadUser : Promise

Returns the current user if exists

deleteUser : Promise

Deletes the current user from the storage/cookies

Immutable JS

Usage of redux-react-session with an immutable store is really simple. Instead of the sessionReducer import the sessionReducer from redux-react-session/immutable, as the following example:

  • Add the session reducer:
import { combineReducers } from 'redux';
import { sessionReducer as session } from 'redux-react-session/immutable';

const reducers = {
  // ... your other reducers here ...
  session
};
const reducer = combineReducers(reducers);

Server Rendering

redux-react-session also provides methods to keep the session with server rendering using cookies. So the session will work on the server side as well as the client side.

Here is an example using server rendering

initServerSession(store, req)

Initialize an instance of the server session service.

This function is used in the server.js to initialize a session service instance in each request.

// server.js
import { sessionService, sessionReducer } from 'redux-react-session';
import { combineReducers, createStore } from 'redux';

// ...
app.use((req, res) => {
  const reducer = combineReducers({
    session: sessionReducer
  });
  // Create a new Redux store instance
  const store = createStore(reducer);

  sessionService.initServerSession(store, req);
  // ...
}
// ...

initSessionService(store, { driver: 'COOKIES' })

Initialize an instance of the client session service, IMPORTANT to set the option 'COOKIES'(this is the way that the client send the session data to the server).

This function is used in the client.js of the server rendering to initialize a session service instance.

// client.js
import { createStore } from 'redux';
import { sessionService } from 'redux-react-session';

const store = createStore(reducer)

initSessionService(store, { driver: 'COOKIES' });

redux-react-session's People

Contributors

bernabe9 avatar darkrift avatar eliyahut123 avatar hitochan777 avatar orf avatar santiestra avatar umpc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

redux-react-session's Issues

Set Expiry manually while Save Session and Save User Method

Hi

Can you add a parameter in saveSession and saveUser Method to set cookie expiry manually instead of assigning at the initial level.

Because consider this use-case. In Login form there is a option called "RememberMe". if the user select this option means we have to set expiry to future date. So for this type of use-case if you allow this default parameter means it will be helpful.

key: 'saveUser',
value: function saveUser(user, expires=null) {
return new Promise(function (resolve) {
if (instance.server) {
instance[_constants.USER_DATA] = user;
instance.store.dispatch((0, _actions.getUserSessionSuccess)(user));
resolve();
} else if (instance.driver === 'COOKIES') {
Cookies.set(_constants.USER_DATA, user, { expires: expires == null ? instance.expires : expires });
instance.store.dispatch((0, _actions.getUserSessionSuccess)(user));
resolve();
} else {
instance.storage.setItem(_constants.USER_DATA, user).then(function (user) {
instance.store.dispatch((0, _actions.getUserSessionSuccess)(user));
resolve();
}).catch(function () {
instance.store.dispatch((0, _actions.getUserSessionSuccess)(user));
Cookies.set(_constants.USER_DATA, user, { expires: expires == null ? instance.expires : expires });
resolve();
});
}
});
}
}

Thanks,
Velu

question: how session validation is being triggered

How session validation (validateSession in sessionOptions) is being triggered?

In one example, the CheckAuth function is being triggered onEnter of a route.

https://github.com/bernabe9/redux-react-session/blob/master/src/index.js#L26

This library uses localforage.

https://github.com/bernabe9/redux-react-session/blob/master/src/index.js#L39-L46

https://github.com/localForage/localForage/blob/master/src/localforage.js#L117-L154

Unfortunately, I did not find what does 360 means as it relates to localforage.

Authentication completed but redirect not happening..

I have used this and authentication is happening very fine but after being authenticated page is not being redirected on required route .

I have strictly followed your documentation but i do't know what wrong i m doing .

Please suggest me if any more step has to be taken..

Thanks in advance ..

Token validation on initSessionService

When the page reload, initSessionService reload the token from the configured storage. But I need to validate the token. May be have some user defined promise to use on refreshFromLocalStorage before dispatch the getUserSessionX action.

Or there is another way to do it ?

ps: I'm not using SSR

Export action Types

Suggested changes in the index:

import * as actionTypes from './actionTypes';

export const sessionActionTypes = actionTypes;

Allow validateSession to return a promise

Locally validating the token is only the first step but the real deal is to know if the server still have that session token active/alive (maybe the server restarted, the session has been killed by some other admin users, etc) so a server call will most likely always be required to determine if the client token is still valid.

Currently the validateSession option must be a pure function that requires an immediate returned value but allowing the returned value to be a promise would allow server validation and fix the described problem.

Update NPM package

Not sure how NPM's publishing system works or if this is already in progress, but it would be super helpful to have the latest version in NPM.

Explanation on initServerSession

Could you explain more about how server sessions work with redux-react-session? In particular, the documentation regarding initServerSession:

// server.js
import { sessionService } from 'redux-react-session';

// ...
app.use((req, res) => {
  const store = createStrore();
  sessionService.initServerSession(store, req);
  // ...
}
// ...

If createStore() comes from redux (I'm assuming createStrore is a typo), what parameters would I need to pass into it? Is there also any other configuration that needs to be done after sessionService.initServerSession(store, req)?

React Router4 - Alternative of OnEnter

Hi,
I am unable to figure out how to put restrictions on private routes. In React Router4, onEnter is removed.

Store listener is not working as the event (@@redux-react-session/GET_SESSION_SUCCESS) is ASYNC.

How to check if the user is authenticated.

@bernabe9 Any help on this is appreciated.

Thank you in Advance.

React Router v4 support

Issue
I was able to login to my application and click around my "authenticated routes" just fine. However, the second I tried to access a route directly, i.e. typing a url in the browser or refreshing the page, I would hit the login screen.
I attempted to follow the React Router v4 Example, but it did not work.

Solution
React Router v4 does not use hooks, but rather relies on the React Component lifecycle. Which means it not possible to call sessionService.checkAuth in the onEnter hook. The IndexRoute component has also been removed.

The following code works like a charm:

import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'

import Dashboard from './Dashboard'
import Home from './Home'
import SignIn from './SignIn'
import SignOut from './SignOut'

class Routes extends Component {
  constructor(props) {
    super(props)
    this.state = {
      loading: true,
      authenticated: false
    }
  }

  componentWillReceiveProps(nextProps) {
    const { session } = nextProps

    this.setState({
      loading: false,
      authenticated: session.authenticated
    })
  }

  render() {
    const state = this.state

    return (
      <div style={appStyles}>
      { state.loading === true ? (
        <p>Loading...</p>
      ) : (
        <div>
          <Router>
            <Switch>
              {/* Always accessible routes*/}
              <Route exact path="/" component={Home}/>
              <div>
                { state.authenticated === false ? (
                <div>
                  {/* Public only routes*/}
                  <Route path="/sign-in" component={SignIn}/>
                </div>
                ) : (
                <div>
                  {/* Private only routes*/}
                  <Route path="/dashboard" component={Dashboard}/>
                  <Route path="/profile" component={Profile}/>
                  <Route path="/sign-out" component={SignOut}/>
                </div>
                )}
              </div>
              <Redirect to='/' />
            </Switch>
          </Router>
        </div>
      )}
      </div>
    )
  }
}

Routes.propTypes = {
  session: PropTypes.object.isRequired
}

const mapStateToProps = (state, ownProps = {}) => {
  return state
}

export default connect(mapStateToProps)(Routes)

initSessionService should return Promise

Hi. Thans for your great work!
I am currently facing an issue of components trying to access session.user before it is ready to be accessed. The problem is that initSessionService calls loadUser in an async manner ( which is perfectly fine), thus, session.user can be accessed when it is not ready.

An example code is show below (Note that unimportant codes are abbreviated).

index.js

sessionService.initSessionService(store, {driver: 'COOKIES'} );
render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
)

App.js

export const App = ({session}) => {
    doSomethingWithUserInfo(session.user)
    ...
}
const mapStateToProps = ({session}) => ({
    session,
});

export default connect(mapStateToProps)(App)

To avoid this problem, I want to make sure that session.user is set before proceeding to the next lines.
One way to achieve this is to return Promise in initSessionService and modify refreshFromLocalStorage a bit (so that it returns the promise that corresponds to loadUser).

If you have another way of solving this issue, please let me know. Otherwise, I am willing to issue an PR!
Thanks!

How to get user information of current session

import {sessionService} from 'redux-react-session'; class AboutUs extends Component { render() { sessionService.loadSession() .then(currentSession => console.log(currentSession)) .catch(err => console.log(err))
this printed out 'undefine', please give me some advice

Missing license

I cannot find the license to use for this project.

License is useful in determining if the project can be used in other projects.

Type missing

Typescript types are missing for this library

Allow an option not to set expiry for cookies

Hi,

Can you provide this feature for COOKIES option.

Generally for Cookies, if we didn't set an "expires" param then it lasts only for the session. It will expired automatically when browser closes.

This feature is very helpful for the logged-in user who forget to logs out the website. Information stored in cookies will get removed whenever the browser gets closed otherwise it will stay there for the time we set for expire parameter

Thanks
Velu

delete session and delete user not working..

Has any one else experienced deleteSession() or deleteUser() not working?

Are there any working examples?

This is what I'm using but it doesn't affect any cookies, etc

    sessionService.deleteSession();
    sessionService.deleteUser();

Immutable Dependency Added to Projects That Don't Use ImmutableReducer

Due to the way index.js defines sessionService and exports ImmutableReducer, there is no way to import sessionService without also importing Immutable. This adds an extra 60kb to our app load, despite the fact ImmutableReducer is never used.

To solve this, break sessionService into a separate file so it can be imported directly:

import sessionService from 'redux-react-session/dist/sessionService`

Redux Thunk - instance.store.dispatch is not a function

Hi,

I am using Redux Thunk and I am getting this message when I try to save the session.
This is my action creator:

export function login(data, history){
  return async function(dispatch){
    const response = await post('/users/login', data);
    if (response.result){
      const {token} = response;
      sessionService.saveSession(token);
      history.push(`/user/${response.id}`);
    } else{
      console.log(response.message);
    }
  }
}

I also tried this.

export function login(data, history){
  return async function(dispatch){
    const response = await post('/users/login', data);
    if (response.result){
      const {token} = response;
      sessionService.saveSession(token)
      .then( () => {
      history.push(`/user/${response.id}`);
      });
    } else{
      console.log(response.message);
    }
  }
}

I could not figure out why.

TypeError: Cannot read property 'server' of undefined

I'm getting this error occasionally when sessionService.loadUser is called.

"TypeError: Cannot read property 'server' of undefined"
index.js?5c1b:278 Uncaught (in promise) TypeError: Cannot read property 'server' of undefined
at eval (index.js?5c1b:278)
at new Promise ()
at Function.loadUser (index.js?5c1b:277)
at currentUser (ProfileForm.js?a96b:42)
at Module.eval (ProfileForm.js?a96b:231)
at eval (ProfileForm.js:325)
at Module../src/components/user/ProfileForm.js (bundle.js:20588)
at webpack_require (bundle.js:768)
at fn (bundle.js:131)
at Module.eval (ProfileContainer.js:17)

bundling failed: ReferenceError: [BABEL]

error: bundling failed: ReferenceError: [BABEL] .../node_modules/redux-react-session/dist/index.js: Unknown option: .../node_modules/react/index.js.Children. Check out http://babeljs.io/docs/usage/options/ for more information about options.

A common cause of this error is the presence of a configuration options object without the corresponding preset name. Example:

Invalid:
  `{ presets: [{option: value}] }`
Valid:
  `{ presets: [['presetName', {option: value}]] }`

For more detailed information on preset configuration, please see https://babeljs.io/docs/en/plugins#pluginpresets-options. (While processing preset: ".../node_modules/react/index.js")
    at Logger.error (.../node_modules/babel-core/lib/transformation/file/logger.js:41:11)
    at OptionManager.mergeOptions (.../node_modules/babel-core/lib/transformation/file/options/option-manager.js:226:20)
    at .../node_modules/babel-core/lib/transformation/file/options/option-manager.js:265:14
    at .../node_modules/babel-core/lib/transformation/file/options/option-manager.js:323:22
    at Array.map (<anonymous>)
    at OptionManager.resolvePresets (.../node_modules/babel-core/lib/transformation/file/options/option-manager.js:275:20)
    at OptionManager.mergePresets (.../node_modules/babel-core/lib/transformation/file/options/option-manager.js:264:10)
    at OptionManager.mergeOptions (.../node_modules/babel-core/lib/transformation/file/options/option-manager.js:249:14)
    at OptionManager.init (.../node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)

Is something wrong with babel versions for devDependencies?

getting GET_SESSION_ERROR after logout or refreshing the page

When I am refreshing my application it's giving me this error is happening and because there is not any data in my local storage it's giving me this error. also, it's happening after deleting session and deleting a user from local storage too.

action @@redux-react-session/GET_SESSION_ERROR @ 23:41:18.365
redux-logger.js:1 prev state {requestList: {…}, DashboardRequestList: {…}, ListShow: {…}, userReducer: {…}, session: {…}, …}
redux-logger.js:1 action {type: "@@redux-react-session/GET_SESSION_ERROR"}
redux-logger.js:1 next state {requestList: {…}, DashboardRequestList: {…}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.