Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server-side authentication #17

Closed
themouette opened this issue Feb 10, 2016 · 4 comments
Closed

Server-side authentication #17

themouette opened this issue Feb 10, 2016 · 4 comments

Comments

@themouette
Copy link

I found out about redux-auth-wrapper on stack overflow and was looking for server side rendering as well.

I might have missed something, but server side, a onEnter callback is required on <Route /> component to handle redirection correctly.

The universal-react-redux-boilerplate tends to confirm.

From my understanding, on way to do it is to add a static property onEnter on UserAuthWrapper(), to use as follow:

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.user, // how to get the user state
  redirectAction: routeActions.replace, // the redux action to dispatch for redirect
  wrapperDisplayName: 'UserIsAuthenticated' // a nice name for this auth check
});

const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState);

const routes = (
  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
        <Route path="login" component={Login}/>
        <Route path="foo" component={UserIsAuthenticated(Foo)} onEnter={connect(UserIsAuthenticated.onEnter)}/>
        <Route path="bar" component={Bar}/>
      </Route>
    </Router>
  </Provider>
);

Did I miss something? Is there another way to achieve HTTP redirection on the server?

@mjrussell
Copy link
Owner

Thanks for bringing this up, I dont use server-side rendering, but I think it would probably be worth my time to write a mini example for using this library with SSR.

I might have missed something, but server side, a onEnter callback is required on component to handle redirection correctly.

The universal-react-redux-boilerplate tends to confirm.

That example uses only the onEnter method for auth so it can fall prey to some of the issues discussed in the motivation section (mainly redux-store updates not resulting in redirects).

I'll try to work on something in the next few days (if you have a very basic example feel free to PR it into the examples to give me a head start).

You are probably right in that there might need to be a combination of onEnter + HOC for SSR. By first using a new static method onEnter for the initial check, and then an HOC to to enforce checks on store updates or nested route changes.

Would be nice to use onEnter solely on the server render but Im not sure if there is a way to check for this. Thanks for the issue! Im going to do some more digging into this and report back

@themouette
Copy link
Author

If it can help, for now, I monkey path the HOC and it works (I did not check for redirect):

import { UserAuthWrapper } from 'redux-auth-wrapper';

/**
 * HOC to protect a route.
 */
export const RequireAuth = UserAuthWrapper({
  authSelector: state => state.authentication.user,
  redirectAction: routeActions.replace,
  failureRedirectPath: '/public',
  wrapperDisplayName: 'RequireAuth',
  allowRedirectBack: true
});
RequireAuth.onEnter = (store, nextState, replace) => {
  const user = store.getState().authentication.user;

  if (!user) {
    replace({
      pathname: '/public',
      state: { redirect: nextState.location.pathname },
    });
  }
};

And on the route:

export default ({ store }) => {
  const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState);

  return (
    <Route>
      <Route path="/public" component={Publi)} />
      <Route path="*" component={RequireAuth(App)}
             onEnter={connect(RequireAuth.onEnter)} />
    </Route>
  );
};

@mjrussell
Copy link
Owner

@themouette

Thanks! Yeah definitely along the lines with what I was thinking. I wonder if the onEnter should have a check to only run if not on the client, something like:

function isClient() {
   return typeof window != 'undefined' && window.document;
}

RequireAuth.onEnter = (store, nextState, replace) => {
  if (!isClient()) {
    const user = store.getState().authentication.user;

    if (!user) {
      replace({
        pathname: '/public',
        state: { redirect: nextState.location.pathname },
      });
    }
  }
};

Maybe this is something that should just be in the example or the docs though? Probably better to let each user decide where they want to run it.

The problem with not including an isClient check is that you essentially are running the check twice on the client if the route is triggered, once in onEnter and another if the onEnter passes and the HOC is returned.

@mjrussell
Copy link
Owner

Release v0.3.0 with onEnter property and info in the README https://github.com/mjrussell/redux-auth-wrapper#server-side-rendering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants