Giter VIP home page Giter VIP logo

redux-auth-wrapper's Introduction

redux-auth-wrapper

npm npm dm Build Status Coverage Status Join the chat at https://gitter.im/mjrussell/redux-auth-wrapper

Decouple your Authentication and Authorization from your components!

npm install --save redux-auth-wrapper

redux-auth-wrapper is a utility library for handling authentication and authorization in react + redux applications.

Read the documentation at https://mjrussell.github.io/redux-auth-wrapper

Version 3

Version 3.x has the same external API as version 2, however it only supports React >= 16.3. It is also tested with react-router v5 and connected-react-router which replaced react-router-redux.

Version 2

Version 2.x is a big internal rewrite! It provides a massive increase in flexibility when using redux-auth-wrapper and also introduces some breaking changes. See the Migration Guide for more details if coming from 1.x. Or check out the Getting Started guide if you've never used redux-auth-wrapper before.

Looking for Version 1.x? You can browse the 1.x README here.

Submitting Issues

Having trouble? First check out the Troubleshooting section of the documentation, and then search the issues, both open and closed for your problem. If you are still having trouble or have a question on using redux-auth-wrapper, please open an issue! You can also ask on the gitter channel.

Examples

Other examples not yet updated to v2:

redux-auth-wrapper's People

Contributors

ahdinosaur avatar carr1005 avatar davidhampgonsalves avatar dekked avatar dependabot[bot] avatar dvemac avatar fullstackforger avatar gaearon avatar gitjeff05 avatar harshmaur avatar jackhowa avatar johanneslumpe avatar johnwiseheart avatar jwickens avatar kambleaa007 avatar lvarayut avatar mehiel avatar mjrussell avatar oklas avatar oyeanuj avatar piuccio avatar quentin-st avatar sebabouche avatar tkvw avatar tpai avatar vieiralucas avatar xmanjack avatar zacaytion 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  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

redux-auth-wrapper's Issues

Duplicated `authData` in store.

Hi,

I have auth and data reducer and I followed tutorial to use UserAuthWrapper. It works ok, but when I see store, I see authData which is exactly same copy of auth in dev tool. I tried React-Router-Redux and React-Router 2.0 with JWT sample and it doesn't show authData in store. What am I missing? Is it caused by the store configuration? Thanks for your help.

Include example/suggestions for local storage

Currently there isn't a great way to use local storage.

The best solution right now is to have a call similar to "what user am I?" maybe like a /api/users/me or similar. This will set the userAuthData in the store if successful and be dispatched on application load. On a 401, you clear this data out of the store.

This way your app doesn't even know about a cookie in localstorage, it just knows if there is a user or not. When you login successfully, you can dispatch the getUser using something like redux-thunk.

Should document this better or provide an alternative way.

One such alternative could be to provide a "isLoggingIn" selector which will display a component of the user's choice while this value is true instead of performing a redirect or showing the authed component

Passing Props Warning React 15.3.0

We have upgraded to React 15.3.0 from 15.1.0 and are now receiving this warning while using your wrapper.

Warning: Unknown props `history`, `location`, `params`, `route`, `routeParams`, `routes` on <span> tag. Remove these props from the element. For details, see https://fb.me/react-unknown-prop
    in span (created by RequireAuthentication(Connect(UserEvaluations)))
    in RequireAuthentication(Connect(UserEvaluations)) (created by Connect(RequireAuthentication(Connect(UserEvaluations))))
    in Connect(RequireAuthentication(Connect(UserEvaluations))) (created by RouterContext)
    in div (created by Gateway)
    in Gateway (created by Connect(Gateway))
    in Connect(Gateway) (created by RouterContext)
    in RouterContext (created by Router)
    in ScrollBehaviorContainer (created by Router)
    in Router
    in Provider

It references this documentation which deals with passing props. My guess is the way that you are passing the props to the loading component (in this case the default is making React upset.

Here are what my auth wrappers look like in case that is helpful or the issue is actually on my side

mport { UserAuthWrapper } from 'redux-auth-wrapper'

export const RequireAuthentication = UserAuthWrapper({
  authSelector: state => state.auth,
  predicate: auth => auth.isAuthenticated,
  authenticatingSelector: state => state.auth.fetching,
  wrapperDisplayName: 'RequireAuthentication'
})

export const IgnoreIfAuthenticated = UserAuthWrapper({
  authSelector: state => state.auth,
  failureRedirectPath: '/',
  predicate: auth => !auth.isAuthenticated,
  authenticatingSelector: state => state.auth.fetching,
  wrapperDisplayName: 'IgnoreIfAuthenticated',
  allowRedirectBack: false
})

Infinite loop due to push?

Hi @mjrussell , I'm using your package in my project and I stumble on this issue where it creates an infinite loop between the new and old url.

For example:
I have a component, ProductDetailComponent with the acceptable Route url
'/product-detail/:id'

I wrapped the component with UserIsAuthenticated

import { UserAuthWrapper } from 'redux-auth-wrapper';
import { routerActions } from 'react-router-redux';


export const UserIsAuthenticated = UserAuthWrapper({
  authSelector: (state) => { return state.authentication; },
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated',
  failureRedirectPath: '/authentication',
  predicate: (user) => { return user.accessKey; }
});

At the first load, I go to /product-detail/1 url, and since the User is not authenticated yet, so I got redirected to /authentication to do the login, and upon successful login, I got redirected again to the original page, /product-detail/1. So far so good.

Now let's say, in the ProductDetailComponent, there's a selectbox to select similar Product. If the user select another similar product, then the app will trigger an action that will 'restart' the component:

export function restartModule(productId) {
  return (dispatch) => {
    dispatch(push('/product-detail' + productId));
    dispatch(resetSettings());
    dispatch(fetchProductDetail(productId));
  };
}

And that's when the infinite loop happened.

I tried to debug it but I didn't get far enough. However, if I commented
dispatch(push('/product-detail' + productId));
the infinite loop didn't happen and application works fine (except the url is still the same, doesn't change to the new productId url).

From my understanding, from the Route configuration, regardless which url that I access:

/product-detail/1
/product-detail/2
/product-detail/3

the app will always mount ProductDetailComponent because they match its url pattern /product-detail/:id, and UserIsAuthenticated should be checked only once, since we are not changing component. So why does the UserIsAuthenticated for ProductDetailComponent get triggered again if push to /product-detail/2 or so on?

Other information, I use react-redux-starter-kit with:

    "react": "^15.0.0",
    "react-dom": "^15.0.0",
    "react-redux": "^4.0.0",
    "react-router": "^2.2.0",
    "react-router-redux": "^4.0.0",
    "redux": "^3.0.0",
    "redux-auth-wrapper": "^0.5.0",

Any pointers to fix this issue? Thanks in advance!

Pass `ownProps` to `authSelector`

Redux passes component properties to mapStateToProps, What do you think about passing them to authSelector as well?

It allow to leverage other Higher Order Components, accept configuration or access route params.

What do you think?

Generic action on auth failure instead of redirect

I would like to use redux-auth-wrapper to optionally render a component (or part of a page) if there is not enough authorisation to view part of the interface.

The use case is, consider you have a page (for example a blog post), that displays a resource. Depending if the current user owns the resource, I would like to display a set of command (for example Edit post, Delete post).

I would create an AuthWrapper component that renders the commands only if the user has enough permissions.

For example, given the following component

const Commands = (onEdit, onDelete) => {
    <div>
          <button onClick={onEdit}>Edit</button>
          <button onClick={onDelete}>Delete</button>
    </div>
});

I would render the Commands component with the AuthWrapper:

const ProtectedCommands = AuthCanEdit(Commands);

// ...

render() {
    return <ProtectedCommands ... />;
}

The AuthCanEdit wrapper is configured to look at the store and check if the user as permission to view the wrapped component.

Such use case could be the motivation to abstract the api so that the action on fail is not only a redirect, but could be stopping a component to render, or conditionally show components.

Is there anything planned to support it? If there is enough interest, we could discuss an api for it.

Motivation Section of the README

  • pros & cons compared to using onEnter hooks
  • consolidate smattering of examples & gists
  • rolling your own can be tricky (infinite loop issue in RSR)

Concatenating user auth

Whats the point about wrapping auth class twice?:

<Route path="admin" component={UserIsAuthenticated(UserIsAdmin(Admin))}/>

I'm just using it once and the result is the same, but I'm sure there's something I can't see.

By the way, wrapperDisplayName should appear in DevTools? Because it just print the action name, USER_LOGGED_IN

This is my code:

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.user,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated'
})
const UserIsAdmin = UserAuthWrapper({
  authSelector: state => state.user,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAdmin',
  predicate: user => user.isAdmin
})

ReactDOM.render(
  <Provider store={store}>
    <div>
      <Router history={history}>
        <Route path="/" component={App}>
          <IndexRoute component={Home}/>
          <Route path="login" component={Login}/>
          <Route path="foo" component={UserIsAuthenticated(Foo)}/>
          <Route path="admin" component={UserIsAdmin(Admin)}/>
        </Route>
      </Router>
      <DevTools />
    </div>
  </Provider>,
  document.getElementById('mount')

This is yours:

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.user,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated'
})
const UserIsAdmin = UserAuthWrapper({
  authSelector: state => state.user,
  redirectAction: routerActions.replace,
  failureRedirectPath: '/',
  wrapperDisplayName: 'UserIsAdmin',
  predicate: user => user.isAdmin,
  allowRedirectBack: false
})

ReactDOM.render(
  <Provider store={store}>
    <div>
      <Router history={history}>
        <Route path="/" component={App}>
          <IndexRoute component={Home}/>
          <Route path="login" component={Login}/>
          <Route path="foo" component={UserIsAuthenticated(Foo)}/>
          <Route path="admin" component={UserIsAuthenticated(UserIsAdmin(Admin))}/>
        </Route>
      </Router>
      <DevTools />
    </div>
  </Provider>,
  document.getElementById('mount')
)

User loaded asyncroniously in browser

My application works with 3rd party API only so I'm going to serve files statically (and I.m unable to initialize the store on the server).
Because of that my app is always redirected to /login before user is loaded and added to the store.

It would be nice to have example or recommendations how to handle this case.

I have following workaround, but I don't like it:

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => {
    return {
      wasRequested: state.isLoggedUserRequested,
      data: state.entities.loggedUser
    };
  },
  redirectAction: (path) => replaceState(null, path.pathname, path.query),
  wrapperDisplayName: 'UserIsAuthenticated',
  allowRedirectBack: false,
  predicate: user => {
    // logged user has not been requested yet - redirect to /login page is not required
    if (!user.wasRequested) {
      return true;
    }
    // user has been requested but user is not logged - redirect to /signin
    else if (user.wasRequested && isEmpty(user.data)) {
      return false;
    }

    return true;
  }
});

isLoggedUserRequested is set to true when request to /users/me has been completed.

Using internationalized URLs

Hello and thank you for this component. I've tried to look over the docs but I'm not exactly sure how to accomplish what I'm doing. My URLs are internationalized (/en-us/dashboard for instance) and I'm having trouble getting the login redirect working. Here is my setup:

Main file with Router:

render((
    <Provider store={store}>
        <Router history={history}>
            <Redirect from="/" to={`/${getCurrentLanguage().lcid}/dashboard`} />
            {routes}
        </Router>
    </Provider>
), document.getElementById('root'));

Routes file:

// On first load make sure that the language in the URL is the same as the
// current language and if not then set it and update the messages in the store.
const ensureLanguageMatch = (nextState, replace, cb) => {
    const lcidFromUrl = nextState.params.lcid;

    if (lcidFromUrl !== getCurrentLanguage().lcid) {
        setCurrentLanguage(getLocale(lcidFromUrl), false);

        store.dispatch(update({
            locale: getCurrentLanguage().locale,
            messages: TRANSLATIONS[getCurrentLanguage().lcid]
        }));
    }

    cb();
};

const UserIsAuthenticated = UserAuthWrapper({
    authSelector: state => {
        return state.user;
    },
    redirectAction: routerActions.replace,
    wrapperDisplayName: 'UserIsAuthenticated'
});

export default (
    <Route path="/" onEnter={ensureLanguageMatch}>
        <Route path=":lcid" component={App}>
            <IndexRoute component={UserIsAuthenticated(DashboardContainer)} />
            <Route path="login" component={UserLogin} />
            <Route path="dashboard" component={UserIsAuthenticated(DashboardContainer)} />
            <Route path="messages" component={UserIsAuthenticated(MessagesContainer)}>
                <IndexRoute component={ConversationsSectionContainer} />
                <Route path=":conversationId" component={MessagesSectionContainer} />
            </Route>
            <Route path="goals" component={Goals} />
            <Route path="learning" component={Learning} />
            <Route path="community" component={Community} />
            <Route path="help" component={Help} />
            <Route path="ui" component={UIKit} />
        </Route>
    </Route>
);

Result of this is that upon page load the user gets redirected to http://localhost:3000/en-us/dashboard but nothing displays (not even my original dashboard component) but the header and footer (which are in App).

By removing the redirectAction in UserIsAuthenticated the user gets redirected to http://localhost:3000/login?redirect=%2Flogin%3Fredirect%3D%252Fen-us%252Fdashboard and again nothing is shown except for the header and footer from App.

I know this is a pretty specific use case but I'd really appreciate if you could help me out in understanding what I'm doing incorrectly and how to alleviate this.

Difficulties integrating UserAuthWrapper into react-boilerplate

Im doing the job integrates redux-auth-wrapper with react-boilerplate,(referred blog) it did not redirect to '/login' by default even set [predicate(authData): Bool] (Function) to false. Please help!
@mjrussell @johnwiseheart @cab @gaearon @DveMac @mxstbr

const UserIsAuthenticated = UserAuthWrapper({
  //authSelector: state => null,
  authSelector: state => state.login.userState,
  predicate: authData=>false,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated'
})
export default function createRoutes(store) {
  // Create reusable async injectors using getHooks factory
  const { injectReducer, injectSagas } = getHooks(store);

  return [
     {
      path: '/home',
      name: 'home',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          System.import('containers/Home/reducer'),
          System.import('containers/Home'),
        ]);

        const renderRoute = loadModule(cb);

        importModules.then(([homeReducer, component]) => {
          injectReducer('Home', homeReducer.default);
          //remain on the route:'/home'
          renderRoute(UserIsAuthenticated(component));
        });

        importModules.catch(errorLoading);
      },
    },  

Is it easily to hack into protected site?

I'm using this library without server side rendering.
Meaning that, all components are actually written in Javascript.

So, i wonder would it easily as an intruder to get into the information without logging in the application?

Wrap HOC around a bunch of routes rather than a specific component

What I mean is something like this:

export default () => {
    return (
        <Route path='/' component={BaseLayout}>
            <IndexRedirect to="/login" />
            <Route path='login' component={LoginView} />
            <UserIsAuthenticated>
                <Route path="conversations" component={ConversationsView } />
                <Route path='*' component={ErrorView} />
            </UserIsAuthenticated>
        </Route>
    )
}

I realize I could simply wrap every single component like so UserIsAuthenticated(Foo), but I'm wondering if there wouldn't be a cleaner way to prevent a bunch of routes from being accessed by a logged out user.

For the record, the above code sample wouldn't work for me. I'm pretty sure it's normal though. Is that something we'd want to be able to do?

Wrapper fails to redirect on initial load

I believe this is a regression introduced in 0.5.1. It disappears completely when I roll back to 0.5.0.

If the authSelector returns null on the initial load of the page, the protected content will not load, but the configured redirect will fail to occur. If I login, the content will be correctly displayed. If I logout the correct redirect will take place.

JWT Token Invalidation

How would you handle a situation in which the auth check passes, because an auth token in present in the store, but then when a subsequent request is fired (i.e. from a button press), it is rejected (401) because the token is invalid?

Ideally this would trigger a redirect to the login page.

I think this is quite straightforward but it might be a useful thing to include in an example as it seems like a common situation.

Server-side authentication

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?

Child route has been remounted

Hi @mjrussell, this is my routes config.

// Redirect to '/setup' if cluster has not been installed.
const ClusterIsInstalled = UserAuthWrapper({
  authSelector: state => state.installationMap,
  authenticatingSelector: state => state.installationMap.get('isFetching'),
  predicate: installationMap => installationMap.get('finished'),
  failureRedirectPath: '/setup',
  allowRedirectBack: false,
});

// Redirect to '/login' if user has not been logged in.
const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.authMap,
  predicate: authMap => authMap.get('isAuthenticated'),
  wrapperDisplayName: 'UserIsAuthenticated',
});

export default (
  <Route path="/" component={App}>
    <Route path="/setup" component={ClusterIsNotInstalled(SetupPage)} />
    <Route path="/login" component={UserIsNotAuthenticated(ClusterIsInstalled(LoginPage))} />
    <Route path="/dashboard" component={UserIsAuthenticated(ClusterIsInstalled(Dashboard))} >
      <IndexRoute component={OverviewPage} />
      <Route path=":resource" component={ResourcePage} />
    </Route>
  </Route>
);

When the browser's url match the resource page route such as "/dashboard/osds", the "ResourcePage" component has been mounted twice. And the second one was occurred after the "GET_CLUSTER_INSTALLATION_SUCCESS" redux action.

This is my console log:

Navigated to http://localhost:3000/dashboard/osds
ResourcePage WillMount          ResourcePage.js?56ee:89
[HMR] connected                 client.js?3ac5:55
ResourcePage WillUnmount        ResourcePage.js?56ee:90
Dashboard WillMount             Dashboard.js?9bc2:55
ResourcePage WillMount          ResourcePage.js?56ee:89

What can i do if i don't want the "ResourcePage" be remount?

Logging out without setting redirect param (whilst allowRedirectBack: true)

Firstly, thanks for the great library. It's been a massive help.

Hopefully I haven't missed anything obvious in the docs. Thanks!

โ€”

Looking at the basic example provided in this repo (where /foo is protected)

  • Is it possible to log out and NOT append the redirect query
    e.g. /foo -> (user presses logout) -> /login
  • ... whilst also ensuring direct links to protected pages by unauthenticated users redirect accordingly?
    e.g. Unauthenticated user visits /foo -> (UserAuthWrapper checks authSelector) -> /login?redirect=%2Ffoo

React-Router-Redux and React-Router 2.0 with JWT example throw error on safari 9.0.3

the example works on chrome but on Safari Version 9.0.3 (9537.86.4.4)

it complains about not finding a variable "fetch" am I missing something?

this what I get on my console
ReferenceError: Can't find variable: fetch (anonymous function)index.js:49 (anonymous function)index.js:8 (anonymous function)bindActionCreators.js:6 loginLoginView.js:20 login login dispatchEvent invokeGuardedCallbackReactErrorUtils.js:70 executeDispatchEventPluginUtils.js:78 executeDispatchesInOrderEventPluginUtils.js:101 executeDispatchesAndReleaseEventPluginHub.js:42 executeDispatchesAndReleaseTopLevelEventPluginHub.js:53 forEach forEachAccumulatedforEachAccumulated.js:22 processEventQueueEventPluginHub.js:258 runEventQueueInBatchReactEventEmitterMixin.js:17 handleTopLevelReactEventEmitterMixin.js:33 handleTopLevelWithoutPathReactEventListener.js:92 handleTopLevelImplReactEventListener.js:72 performTransaction.js:135 batchedUpdatesReactDefaultBatchingStrategy.js:61 batchedUpdatesReactUpdates.js:93 dispatchEventReactEventListener.js:203 (anonymous function)

Cannot resolve module 'babel'

Hi there,
I'm trying to run the example, and facing this issue, which I can't seem to solve. It would appear to me to be an issue when trying to run babel on the root src directory - but this is after doing an npm install there too.

ERROR in /Users/John/projects/redux-auth-wrapper/src/index.js
Module not found: Error: Cannot resolve module 'babel' in /Users/John/projects/redux-auth-wrapper/src
 @ /Users/John/projects/redux-auth-wrapper/src/index.js 12:15-35

Example failing

The example here is failing with the error:

Uncaught Error: imports[1] for react-transform-catch-errors does not look like a React component.

Redirecting to external login

Hi, how would you configure the auth wrapper to redirect to an external login (in this case an OIDC provider)?

Currently have:

export const redirectToLogin = () => {
    window.location = 'http://anotheraddress';
    return createAction(actionTypes.REDIRECT_TO_LOGIN)();
};

const userIsAuthenticated = UserAuthWrapper({
    authSelector: () => ...,
    wrapperDisplayName: 'UserIsAuthenticated',
    allowRedirectBack: false,
    redirectAction: () => redirectToLogin(),
});

This redirects but will keep dispatching the REDIRECT_TO_LOGIN action until the external login page is loaded (which if down means a stack overflow).

After successful login app does not automatically redirect

I've been struggling with this for last several hours.

  1. I have a "protected" route
  2. When I goto, wrapper redirects me to the /login page with redirect=users
  3. When I successfully logs in user object is get populated with data
  4. But wrapper does not redirect to 'users' page
  • neither render nor componentWillReceiveProps get executed when user logs in. It seems like the wrapper does receive any updates when application state changes.
  • If I press 'users' link in the app after login wrapper does not restrict access anymore

Please help me with some ideas... My head is blowing out with redux and actions/state updates propagation :'(

UserAuthWrapper don't re-check for authentication

Hi there! I'm using Immutable.js, so my whole state is immutable.

I've build wrapper with:

import { push } from 'react-router-redux'

const userIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.get('auth').toJS(),
  redirectAction: push,
  predicate: auth.isAuthenticated
})

But UserAuthWrapper don't re-check for authentication after I change isAuthenticated to true (e.g. neither authSelector not predicate is called). What am I missing?

Example of displaying a snackbar / toast / notification on redirect?

Instead of redirecting to a route where a user can authenticate (like /login), I'd like to redirect the user and show some messages. An example from README:

// Regular authentication & redirect to login from before
const UserIsAuthenticated = UserAuthWrapper({ ... })

// Admin Authorization, redirects non-admins to /app
const UserIsAdmin = UserAuthWrapper({
  failureRedirectPath: '/app',
  predicate: user => user.isAdmin,
  ...
})

<Route path="foo" component={UserIsAuthenticated(UserIsAdmin(Admin))}/>

I really think the user would like to know why he/she is redirected to /app. So I have a custom snackbar(toast, notification, or however you call the component that displays a breif feedback) integrated with redux state. I am trying to wrap my head around this, but not sure how to capture redirection event and dispatch an action accordingly. Any ideas?

The way I currently set up the snackbar is this:

// actions.js
const ADD_SNACKBARS = 'ADD_SNACKBARS';
const DELETE_SNACKBARS = 'DELETE_SNACKBARS';

export const addSnackbars = ({ type, text }) => ({ ... });
export const deleteSnackbars = (id) => ({ ... });

// reducer.js
export default (state = {}, { type, payload }) => {
  switch (type) {
    case ADD_SNACKBARS:
      return { ... };
    case DELETE_SNACKBARS:
      return { ... };
    default:
      return state;
  }
};

// AppContainer.js
class AppContainer extends Component {
  render() {
    return (
      <div>
        <NavigationContainer />
        <SnackbarListContainer /> // Display messages when dispatched and re-rendered
        {this.props.children}
      </div>
    )  
  }
}

Redirecting Already authorized users to a specific route

I've been looking over the docs for a while now and I'm unable to come up with a way to do this. I'm not sure if it's possible currently, or if this might be an enhancement request.

What I would like to do is redirect users who are already authorized when they try to access certain routes (i.e. /login or /signup). I would redirect the users to the route that they recieve after loggin in successfully (in my app it's currently /dashboard).

It's basically like the failureRedirect option arg except more like 'authenticatedRedirect' or something.

Your package has been a great help so far!

Handling two different user roles

Hi everyone,

I have a question, i ma not sure which is the correct approach.

I have two roles "admin", "user". Both of them have dashboards that i want to show on "/" route. When admin is logged in he can see his version of dashboard and when user is logged in he can see his version of dashboard. Both dashboards should be display on "/" route.

If i do something like this:

<Route path="/" component={UserIsAuthenticated(UserIsAdmin(AdvertiserLayout))}> </Route>
<Route path="/" component={UserIsAuthenticated(UserIsAdvertiser(AdvertiserLayout))}> </Route>

This is not working properly, it works ok if i login as Admin, but if i login as user i am redirected to login because UserIsAdmin condition is not matched.

Should i change my approach, is there any other way?

an integration issue with redux-router and server rendering.

according to the documentation I need to use the workaround for server rendering
That requires passing a redux store into the connect wrapper.

const getRoutes = (store) => {
  const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState);
return (
    <Route>
      <Route path="/" component={App}>
        <Route path="login" component={Login}/>
        <Route path="foo"
           component={UserIsAuthenticated(Foo)}
           onEnter={connect(UserIsAuthenticated.onEnter)} 
         />
      </Route>
    </Route>
  );
};

From another side the redux-router middleware demands routes to be created first.

// Compose reduxReactRouter with other store enhancers
const store = compose(
  applyMiddleware(m1, m2, m3),
  reduxReactRouter({
    routes,
    createHistory
  }),
  devTools()
)(createStore)(reducer);

I cannot create store without routs and routs without store.
Is any workaround available?

Not redirecting to /login properly

I'm trying to use your library with no luck whatsoever.

The condition seems to be working because if I set authSelector: state => state it goes through the protected route with no problem.
But when I use the proper authSelector I end up in the protected route but with a blank page.

Bootstrap:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { browserHistory, Router } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import configureStore from './configureStore';
import routes from './routes';

// Get the application-wide store instance, prepopulating with state from the server where available.
const initialState = window.initialReduxState;
const store = configureStore(initialState);
const history = syncHistoryWithStore(browserHistory, store);

// This code starts up the React app when it runs in a browser. It sets up the routing configuration
// and injects the app into a DOM element.
ReactDOM.render(
  <Provider store={ store }>
    <Router history={ history } children={ routes } />
  </Provider>,
  document.getElementById('react-app')
);

Routes (imported and added as children to the parent Router:

  <Route>
    <Route path='/login' onEnter={ redirectToYammerAuth } />
    <Route path='/stream' component={ UserIsAuthenticated(Stream) } />
    <Route path='/yammer/callback' component={ YammerCallback } />

    <Route component={Layout}>
      <Route path='/' components={{ body: Home }} />
      <Route path='/counter' components={{ body: Counter }} />
      <Route path='/fetchdata' components={{ body: FetchData }}>
        <Route path=':startDateIndex' /> { /* Optional route segment that does not affect NavMenu highlighting */ }
      </Route>
    </Route>
  </Route>;

AuthWrapper:

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.currentUser.id, // how to get the user state
  redirectAction: push,
  wrapperDisplayName: 'UserIsAuthenticated' // a nice name for this auth check
});

So when state.currentUser.id is falsy it should redirect to /login. As I said, it seems to properly understand that it should redirect but it's not working.
The following action is triggered:
image

And this is what the component hierarchy looks like:
image

If it helps, I've cloned this repo and I haven't changed anything besides adding a few components and the auth/routes logic.

Consider including a TypeScript definition file

TypeScript is becoming more popular (angular 2 is written in TS and also some other "big boys" that I can't remember now too).

In case you're interested to add a d.ts definition file for this library you may want to start reading this and this.

React Native branch?

Would it be possible to create a branch that implements this for React Native?

User object is loaded async and not ready when userAuthWrapper does it's thing

  1. So the userAuthWrapper is in place and it works
  2. The user is loaded async (via saga) to retrieve the userObj.
  3. the routing kicks in and userAuthWrapper checks the state for my userObj
  4. my async call isn't ready.
  5. userAuthWrapper redirects me to /Login
  6. async call is ready state changes with data userObj
    7 userAuthWrapper rechecks is called and rechecks (but is to late because my path is /login)

So what to do?
i made an other wrapper something like
loadUserPromise.then( () => { DO_AUTHENTICATION_WRAPPER() });

But i'm not sure this is how things should be like.

oh and could some one explain the authenticatingSelector and (authSelector)

Thanks in advance
Marino.

How to use with external oauth authentication?

I'm trying to set up redux-auth-wrapper to authenticate with Yammer client-side flow (which is normal oauth 2 token authentication).

I don't do any authentication on my own, I just leverage Yammer's. So, basically, all I have to do is redirect the browser to https://www.yammer.com/dialog/oauth?client_id=[:client_id]&redirect_uri=[:redirect_uri]&response_type=tokenand after authentication and authorization, the browser redirects to a redirect uri I've specified in the Yammer app settings which is in the form of:

http://mydomain.com/yammer/callback#token=THETOKEN

From there, I just grab the token from the hash and save it to the redux store.

The route that needs authentication is /stream. I want to avoid unnecessary location changes. So, ideally, the flow should be something like.

  1. Non-authenticated user goes to /stream.
  2. redux-auth-wrapper redirects to the external Yammer authentication page.
  3. After authentication/authorization, Yammer redirects to my callback uri which grabs and saves the token to the user store, hence authenticating the user to the app.

Is this approach possible with redux-auth-wrapper?

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.