├── .babelrc
├── .bookignore
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE.txt
├── README.md
├── SUMMARY.md
├── _layouts
└── website
│ └── page.html
├── book.json
├── docs
├── API.md
├── AdvancedUsage
│ ├── OtherRouters.md
│ ├── ReactRouter3.md
│ └── Redux.md
├── Getting-Started
│ ├── HidingAlternate.md
│ ├── NestingWrappers.md
│ ├── Overview.md
│ ├── ReactNative.md
│ ├── ReactRouter3.md
│ └── ReactRouter4.md
├── Migrating.md
└── Troubleshooting.md
├── examples
├── react-router-3
│ ├── .babelrc
│ ├── README.md
│ ├── actions
│ │ └── user.js
│ ├── app.js
│ ├── auth.js
│ ├── components
│ │ ├── Admin.js
│ │ ├── App.js
│ │ ├── Foo.js
│ │ ├── Home.js
│ │ ├── Loading.js
│ │ ├── Login.js
│ │ └── index.js
│ ├── constants.js
│ ├── index.html
│ ├── package.json
│ ├── reducers
│ │ ├── index.js
│ │ └── user.js
│ ├── webpack.config.babel.js
│ └── yarn.lock
└── react-router-4
│ ├── .babelrc
│ ├── README.md
│ ├── actions
│ └── user.js
│ ├── app.js
│ ├── auth.js
│ ├── components
│ ├── Admin.js
│ ├── App.css
│ ├── App.js
│ ├── Home.js
│ ├── Loading.js
│ ├── Login.js
│ └── Protected.js
│ ├── constants.js
│ ├── index.html
│ ├── package.json
│ ├── reducers
│ ├── index.js
│ └── user.js
│ ├── webpack.config.babel.js
│ └── yarn.lock
├── package.json
├── runTests.sh
├── src
├── authWrapper.js
├── connectedAuthWrapper.js
├── helper
│ └── redirect.js
├── history3
│ ├── locationHelper.js
│ └── redirect.js
├── history4
│ ├── locationHelper.js
│ └── redirect.js
├── index.js
└── redirect.js
├── test
├── authWrapper-test.js
├── helpers.js
├── init.js
├── redirectBase-test.js
├── rrv3-test.js
└── rrv4-test.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react", "stage-0"],
3 | "plugins": [
4 | ["transform-decorators-legacy"],
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.bookignore:
--------------------------------------------------------------------------------
1 | src/
2 | lib/
3 | coverage
4 | test/
5 | examples/
6 | package.json
7 | .babelrc
8 | .eslintrc
9 | .gitignore
10 | .travis.yml
11 | CHANGELOG.md
12 | LICENSE.txt
13 | runTests.sh
14 | .node-version
15 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules/*
2 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "settings": {
3 | "react": {
4 | "version": "detect"
5 | }
6 | },
7 | "parser": "babel-eslint",
8 | "extends": [
9 | "eslint:recommended",
10 | "plugin:react/recommended"
11 | ],
12 | "rules": {
13 | "react/prop-types": 0,
14 | "react/display-name": 0,
15 | "react/no-string-refs": 0
16 | },
17 | "env": {
18 | "browser": true,
19 | "node": true
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib
2 | examples/**/bundle.js
3 | node_modules
4 | coverage
5 | npm-debug.log
6 | .idea/
7 | _book
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | cache:
4 | directories:
5 | - node_modules
6 | node_js:
7 | - "8"
8 | - "10"
9 | - "12"
10 | env:
11 | - REACT_ROUTER_VERSION=3
12 | - REACT_ROUTER_VERSION=4
13 | script:
14 | - yarn run lint
15 | - ./runTests.sh
16 | after_success:
17 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
18 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [HEAD](https://github.com/mjrussell/redux-auth-wrapper/compare/v3.0.0...HEAD)
2 | -Nothing yet
3 |
4 | ## [3.0.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v2.1.0...v3.0.0)
5 | - **Breaking Change:** Fix deprecated lifecyle method for react 16.3+ support[#250](https://github.com/mjrussell/redux-auth-wrapper/pull/250) (contributed by @JackHowa)
6 | - Dependency upgrades for react 16.3 support
7 |
8 | ## [2.1.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v2.0.3...v2.1.0)
9 | - Upgrade deps and relax bounds [#244](https://github.com/mjrussell/redux-auth-wrapper/pull/244)
10 |
11 | ## [2.0.3](https://github.com/mjrussell/redux-auth-wrapper/compare/v2.0.2...v2.0.3)
12 | - Warning fix for React 16.3+ [#235](https://github.com/mjrussell/redux-auth-wrapper/pull/235) (contributed by @tpai)
13 |
14 | ## [2.0.2](https://github.com/mjrussell/redux-auth-wrapper/compare/v2.0.1...v2.0.2)
15 | - **Bugfix:** Prevents unnecessary re-renders on child subcomponents on state changes [#187](https://github.com/mjrussell/redux-auth-wrapper/issues/187)
16 |
17 | ## [2.0.1](https://github.com/mjrussell/redux-auth-wrapper/compare/v2.0.0...v2.0.1)
18 | - **Bugfix:** Adds empty main with index.js for webpack ddl support (Contributed by @victorouse)
19 |
20 | ## [2.0.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v1.1.0...v2.0.0)
21 | **BREAKING CHANGES** Version 2.0 include several new changes! See https://mjrussell.github.io/redux-auth-wrapper/docs/Migrating.html for migrating from 1.x
22 |
23 | ## [1.1.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v1.0.0...v1.1.0)
24 | - **Feature:** Support hash fragments in building the redirect location [#121](https://github.com/mjrussell/redux-auth-wrapper/issues/121)
25 | - **Feature:** Upgrade to proptypes package after React 15.5 deprecation [#147](https://github.com/mjrussell/redux-auth-wrapper/pull/147) (Contributed by @jruhland)
26 |
27 | ## [1.0.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.10.0...v1.0.0)
28 | - **Bugfix:** Redirection preserves query params in the redirect path. [#111](https://github.com/mjrussell/redux-auth-wrapper/pull/111)
29 |
30 | ## [0.10.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.9.0...v0.10.0)
31 | - **Feature:** `allowRedirectBack` can also take a selector function that returns a bool instead of a bool. [#93](https://github.com/mjrussell/redux-auth-wrapper/pull/93) (Contributed by @oyeanuj)
32 |
33 | ## [0.9.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.8.0...v0.9.0)
34 | - **Bugfix:** Don't pass down auth wrapper props besides authData [#81](https://github.com/mjrussell/redux-auth-wrapper/issues/81)
35 | - **Feature:** Add propMapper function to restrict passed through props [#28](https://github.com/mjrussell/redux-auth-wrapper/issues/28)
36 | - **Bugfix/Breaking Change:** onEnter now checks isAuthenticating for redirection [#89](https://github.com/mjrussell/redux-auth-wrapper/issues/89)
37 | - **Feature:** onEnter selectors receive nextState as the second argument instead of null [#90](https://github.com/mjrussell/redux-auth-wrapper/issues/90)
38 |
39 | ## [0.8.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.7.0...v0.8.0)
40 | - **Feature:** FailureComponent to not redirect and either hide or show a different component on auth failure [#61](https://github.com/mjrussell/redux-auth-wrapper/pull/61). (Contributed by @mehiel)
41 | - **Feature:** Pass auth data as props to Loading Component [#75](https://github.com/mjrussell/redux-auth-wrapper/issues/75)
42 | - **Breaking Change:** When rendering an "empty" component such as the default LoadingComponent and when the user is about
43 | to be redirect, return `null` so React will omit it instead of an empty `div`.
44 | - **Breaking Change:** Don't need to import React Native compatible from lib.
45 |
46 | ## [0.7.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.6.0...v0.7.0)
47 | - **Bugfix:** Don't render subroutes as children in default LoadingComponent [#63](https://github.com/mjrussell/redux-auth-wrapper/pull/63)
48 | - **Bugfix/Breaking Change:** Change default LoadingComponent to a `div` and use the React native default empty element [#63](https://github.com/mjrussell/redux-auth-wrapper/pull/63)
49 |
50 | ## [0.6.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.5.2...v0.6.0)
51 | - **Feature:** `failureRedirectPath` can be a function of state and props [#57](https://github.com/mjrussell/redux-auth-wrapper/pull/57)
52 | - **Feature:** option to change the query param name with `redirectQueryParamName` [#57](https://github.com/mjrussell/redux-auth-wrapper/pull/57)
53 |
54 | ## [0.5.2](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.5.1...v0.5.2)
55 | - **BugFix:** Fixes bug introduced in v0.5.1 that prevented redirection when only isAuthenticating changed [#49](https://github.com/mjrussell/redux-auth-wrapper/issues/49)
56 |
57 | ## [0.5.1](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.5.0...v0.5.1)
58 | - **BugFix:** Adds safeguard to prevent infinite redirects from the wrapper [#45](https://github.com/mjrussell/redux-auth-wrapper/pull/45)
59 |
60 | ## [0.5](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.4.0...v0.5.0)
61 | - **Feature:** Adds `isAuthenticating` selector and `LoadingComponent`
62 | [#35](https://github.com/mjrussell/redux-auth-wrapper/pull/35). (Contributed by @cab)
63 |
64 | ## [0.4](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.3.0...v0.4.0)
65 | - **Feature:** Adds React Native support [#33](https://github.com/mjrussell/redux-auth-wrapper/pull/33)
66 |
67 | ## [0.3](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.2.1...v0.3.0)
68 | - **Feature:** Adds `ownProps` param to `authSelector` [#21](https://github.com/mjrussell/redux-auth-wrapper/pull/21)
69 | - **Feature:** Adds `onEnter` function for Server Side Rendering support [#19](https://github.com/mjrussell/redux-auth-wrapper/pull/19)
70 | - **Breaking:** Removes arg style syntax that was deprecated in 0.2
71 |
72 | ## [0.2.1](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.2.0...v0.2.1)
73 | - router context is only required if no redirectAction
74 |
75 | ## [0.2.0](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.1.1...v0.2.0)
76 | - **Feature:** new redirectAction config arg, removes dependency on a redux-routing implementation [#13](https://github.com/mjrussell/redux-auth-wrapper/issues/13)
77 | - **Feature:** New config object syntax for AuthWrapper [#12](https://github.com/mjrussell/redux-auth-wrapper/issues/12)
78 | - **Deprecation:** Deprecates AuthWrapper args syntax [#12](https://github.com/mjrussell/redux-auth-wrapper/issues/12)
79 | - **Feature:** Hoists wrapped component's statics up to the returned component
80 |
81 | ## [0.1.1](https://github.com/mjrussell/redux-auth-wrapper/compare/v0.1.0...v0.1.1)
82 | - Fixes the bad npm publish
83 |
84 | ## [0.1.0](https://github.com/mjrussell/redux-auth-wrapper/compare/fcbf49d0abcae7075daa146c05edff1b735b3a16...v0.1.0)
85 | - First release!
86 | - Adds AuthWrapper with args syntax
87 | - Examples using Redux-Simple-Router (now React-Router-Redux)
88 | - Lots of tests
89 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mjrussell@users.noreply.github.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Matthew Russell
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # redux-auth-wrapper
2 |
3 | [](https://www.npmjs.com/package/redux-auth-wrapper)
4 | [](https://www.npmjs.com/package/redux-auth-wrapper)
5 | [](https://travis-ci.org/mjrussell/redux-auth-wrapper)
6 | [](https://coveralls.io/github/mjrussell/redux-auth-wrapper?branch=master)
7 | [](https://gitter.im/mjrussell/redux-auth-wrapper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
8 |
9 | **Decouple your Authentication and Authorization from your components!**
10 |
11 | `npm install --save redux-auth-wrapper`
12 |
13 | redux-auth-wrapper is a utility library for handling authentication and authorization in react + redux applications.
14 |
15 | Read the documentation at https://mjrussell.github.io/redux-auth-wrapper
16 |
17 | ## Version 3
18 | 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](https://github.com/supasate/connected-react-router) which replaced [react-router-redux](https://github.com/reactjs/react-router-redux).
19 |
20 | ## Version 2
21 |
22 | 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](https://mjrussell.github.io/redux-auth-wrapper/docs/Migrating.html) for more details if coming from 1.x. Or check out the [Getting Started](https://mjrussell.github.io/redux-auth-wrapper/docs/Getting-Started/Overview.html) guide if you've never used redux-auth-wrapper before.
23 |
24 | Looking for Version 1.x? You can browse the 1.x README [here](https://github.com/mjrussell/redux-auth-wrapper/tree/1.x).
25 |
26 | ## Submitting Issues
27 |
28 | Having trouble? First check out the [Troubleshooting](https://mjrussell.github.io/redux-auth-wrapper/docs/Troubleshooting.html) 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.
29 |
30 | ## Examples
31 | * [React Router 3](https://github.com/mjrussell/redux-auth-wrapper/tree/master/examples/react-router-3)
32 | * [React Router 4/5](https://github.com/mjrussell/redux-auth-wrapper/tree/master/examples/react-router-4)
33 |
34 | Other examples not yet updated to v2:
35 | * [Redux-Router and React-Router 1.0 with JWT](https://github.com/mjrussell/react-redux-jwt-auth-example/tree/auth-wrapper)
36 | * [React-Router-Redux and React-Router 2.0 with JWT](https://github.com/mjrussell/react-redux-jwt-auth-example/tree/react-router-redux)
37 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | ## Table of Contents
2 |
3 | * [Read Me](README.md)
4 | * [Getting Started](docs/Getting-Started/Overview.md)
5 | * [React Router 3](docs/Getting-Started/ReactRouter3.md)
6 | * [React Router 4](docs/Getting-Started/ReactRouter4.md)
7 | * [React Native](docs/Getting-Started/ReactNative.md)
8 | * [Hiding and Alternate Components](docs/Getting-Started/HidingAlternate.md)
9 | * [Nesting Wrappers](docs/Getting-Started/NestingWrappers.md)
10 | * [Migrating from V1](docs/Migrating.md)
11 | * [Troubleshooting](docs/Troubleshooting.md)
12 | * [API](docs/API.md)
13 | * Advanced Usage
14 | * [Integrating with other Routers](docs/AdvancedUsage/OtherRouters.md)
15 | * [React Router3 and SSR](docs/AdvancedUsage/ReactRouter3.md)
16 | * [Advanced Redux](docs/AdvancedUsage/Redux.md)
17 |
--------------------------------------------------------------------------------
/_layouts/website/page.html:
--------------------------------------------------------------------------------
1 | {% extends template.self %}
2 |
3 | {% block head %}
4 | {{ super() }}
5 |
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/book.json:
--------------------------------------------------------------------------------
1 | {
2 | "gitbook": "3.2.2",
3 | "plugins": ["prism@1.0.0", "-highlight", "github", "github-edit", "heading-anchors", "ga@1.0.1"],
4 | "pluginsConfig": {
5 | "github": {
6 | "url": "https://github.com/mjrussell/redux-auth-wrapper"
7 | },
8 | "ga": {
9 | "token": "UA-102064405-1"
10 | },
11 | "github-edit": {
12 | "repo": "mjrussell/redux-auth-wrapper",
13 | "branch": "master"
14 | },
15 | "sharing": {
16 | "facebook": false,
17 | "twitter": true,
18 | "google": false,
19 | "weibo": false,
20 | "instapaper": false,
21 | "vk": false
22 | },
23 | "theme-default": {
24 | "styles": { }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/API.md:
--------------------------------------------------------------------------------
1 | ## API
2 |
3 | #### How to read the API
4 |
5 | * Parameter names beginning with `?` are optional
6 | * `HigherOrderComponent` is a function of type:
7 | ```
8 | ReactClass | ReactFunctionalComponent | string =>
9 | ReactClass | ReactFunctionalComponent | string
10 | ```
11 |
12 | ## Redirection Helpers (React Router 3/History v3)
13 |
14 | ### `connectedRouterRedirect`
15 |
16 | ```js
17 | import { connectedRouterRedirect } from 'redux-auth-wrapper/history3/redirect'
18 |
19 | connectedRouterRedirect({
20 | redirectPath: string | (state: Object, ownProps: Object) => string,
21 | authenticatedSelector: (state: Object, ownProps: Object) => boolean,
22 | ?authenticatingSelector: (state: Object, ownProps: Object) => boolean,
23 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
24 | ?wrapperDisplayName: string,
25 | ?allowRedirectBack: boolean | (nextState: Object, redirectPath: String) => boolean,
26 | ?redirectQueryParamName: string
27 | }): HigherOrderComponent
28 | ```
29 |
30 | ### `connectedReduxRedirect`
31 |
32 | ```js
33 | import { connectedReduxRedirect } from 'redux-auth-wrapper/history3/redirect'
34 |
35 | connectedReduxRedirect({
36 | redirectPath: string | (state: Object, ownProps: Object) => string,
37 | authenticatedSelector: (state: Object, ownProps: Object) => boolean,
38 | ?authenticatingSelector: (state: Object, ownProps: Object) => boolean,
39 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
40 | ?wrapperDisplayName: string,
41 | ?allowRedirectBack: boolean | (nextState: Object, redirectPath: String) => boolean,
42 | ?redirectQueryParamName: string
43 | }): HigherOrderComponent
44 | ```
45 |
46 | ### `createOnEnter`
47 |
48 | ```js
49 | import { createOnEnter } from 'redux-auth-wrapper/history3/redirect'
50 |
51 | createOnEnter({
52 | redirectPath: string | (state: Object, nextState: Object) => string,
53 | authenticatedSelector: (state: Object, nextState: Object) => boolean,
54 | ?authenticatingSelector: (state: Object, nextState: Object) => boolean,
55 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
56 | ?wrapperDisplayName: string,
57 | ?allowRedirectBack: boolean | (nextState: Object, redirectPath: String) => boolean,
58 | ?redirectQueryParamName: string
59 | }): (store: Object, nextState: Object: replace: (location: Object => void))
60 | ```
61 |
62 | ### `locationHelperBuilder`
63 |
64 | Helper used by the redirection and useful for pulling the redirectPath out of the query params.
65 |
66 | ```js
67 | import locationHelperBuilder from 'redux-auth-wrapper/history3/locationHelper'
68 |
69 | locationHelperBuilder({
70 | ?redirectQueryParamName: string,
71 | ?locationSelector: (props: Object) => LocationObject
72 | }) : LocationHelper
73 |
74 |
75 | LocationHelper: {
76 | getRedirectQueryParam: (props: Object) => string,
77 | createRedirectLoc: allowRedirectBack: boolean => (nextState: Object, redirectPath: string) => LocationObject,
78 | }
79 | ```
80 |
81 | ## Redirection Helpers (React Router 4/History v4)
82 |
83 | ### `connectedRouterRedirect`
84 |
85 | ```js
86 | import { connectedRouterRedirect } from 'redux-auth-wrapper/history4/redirect'
87 |
88 | connectedRouterRedirect({
89 | redirectPath: string | (state: Object, ownProps: Object) => string,
90 | authenticatedSelector: (state: Object, ownProps: Object) => boolean,
91 | ?authenticatingSelector: (state: Object, ownProps: Object) => boolean,
92 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
93 | ?wrapperDisplayName: string,
94 | ?allowRedirectBack: boolean | (nextState: Object, redirectPath: String) => boolean,
95 | ?redirectQueryParamName: string
96 | }): HigherOrderComponent
97 | ```
98 |
99 | ### `connectedReduxRedirect`
100 |
101 | ```js
102 | import { connectedReduxRedirect } from 'redux-auth-wrapper/history4/redirect'
103 |
104 | connectedReduxRedirect({
105 | redirectPath: string | (state: Object, ownProps: Object) => string,
106 | redirectAction: (location: Object) => ReduxAction,
107 | authenticatedSelector: (state: Object, ownProps: Object) => boolean,
108 | ?authenticatingSelector: (state: Object, ownProps: Object) => boolean,
109 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
110 | ?wrapperDisplayName: string,
111 | ?allowRedirectBack: boolean | (nextState: Object, redirectPath: String) => boolean,
112 | ?redirectQueryParamName: string
113 | }): HigherOrderComponent
114 | ```
115 |
116 | ### `locationHelperBuilder`
117 |
118 | ```js
119 | import locationHelperBuilder from 'redux-auth-wrapper/history4/locationHelper'
120 |
121 | locationHelperBuilder({
122 | ?redirectQueryParamName: string,
123 | ?locationSelector: (props: Object) => LocationObject
124 | }) : LocationHelper
125 |
126 |
127 | LocationHelper: {
128 | getRedirectQueryParam: (props: Object) => string,
129 | createRedirectLoc: allowRedirectBack: boolean => (nextState: Object, redirectPath: string) => LocationObject,
130 | }
131 | ```
132 |
133 | ## Other Wrappers
134 |
135 | ### `authWrapper`
136 |
137 | ```js
138 | import authWrapper from 'redux-auth-wrapper/authWrapper'
139 |
140 | authWrapper({
141 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
142 | ?FailureComponent: ReactClass | ReactFunctionalComponent | string,
143 | ?wrapperDisplayName: string
144 | }): HigherOrderComponent
145 | ```
146 |
147 | The returned Component after applying a Component to the HOC takes as props `isAuthenticated` and `isAuthenticating`, both of which are booleans. `isAuthenticating` defaults to `false`.
148 |
149 | ### `connectedAuthWrapper`
150 |
151 | ```js
152 | import connectedAuthWrapper from 'redux-auth-wrapper/connectedAuthWrapper'
153 |
154 | connectedAuthWrapper({
155 | authenticatedSelector: (state: Object, ownProps: Object) => boolean,
156 | ?authenticatingSelector: (state: Object, ownProps: Object) => boolean,
157 | ?AuthenticatingComponent: ReactClass | ReactFunctionalComponent | string,
158 | ?FailureComponent: ReactClass | ReactFunctionalComponent | string,
159 | ?wrapperDisplayName: string
160 | }): HigherOrderComponent
161 | ```
162 |
163 | ## Other Helpers
164 |
165 | Documentation in progress!
166 |
--------------------------------------------------------------------------------
/docs/AdvancedUsage/OtherRouters.md:
--------------------------------------------------------------------------------
1 | # Integrating with other Routers
2 |
3 | Help us improve this documentation by submitting a pull request!
4 |
--------------------------------------------------------------------------------
/docs/AdvancedUsage/ReactRouter3.md:
--------------------------------------------------------------------------------
1 | # React Router 3 Advanced Usage
2 |
3 | ## Protecting Multiple Routes
4 |
5 | Because routes in React Router 3 are not required to have paths, you can use nesting to protect multiple routes without applying
6 | the wrapper multiple times.
7 | ```js
8 | const Authenticated = userIsAuthenticated(({ children, ...props }) => React.cloneElement(children, props));
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ```
19 |
20 | One thing to note is that if you use named children routes (TODO example) then you may need to use a different approach than `cloneElement` with the `children` prop.
21 |
22 | ## Server Side Rendering
23 |
24 | If you are using redux-auth-wrapper for redirection in apps that use Server Side Rendering you may need to use the `onEnter`. This is because in most cases your server should redirect users before sending down the client HTML.
25 |
26 | ```js
27 | import { createOnEnter } from '../src/history3/redirect'
28 |
29 | const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState)
30 |
31 | const userIsAuthenticated = connectedReduxRedirect({
32 | redirectPath: 'unprotected',
33 | authenticatedSelector: state => state.user !== null,
34 | })
35 |
36 | const onEnter = createOnEnter({
37 | redirectPath: 'unprotected',
38 | authenticatedSelector: state => state.user !== null,
39 | })
40 |
41 |
42 |
43 |
45 | ```
46 |
47 | During onEnter, selectors such as `authenticatedSelector`, `authenticatingSelector`, and `failureRedirectPath` (if you are using)
48 | the function variation, will receive react-router's `nextState` as their second argument instead of the component props.
49 |
50 | ### With nested wrappers
51 |
52 | To implement SSR with nested wrappers, you will have to provide a function to chain `onEnter` functions of each wrapper.
53 |
54 | ```js
55 | const onEnterAuth = createOnEnter({
56 | redirectPath: 'unprotected',
57 | authenticatedSelector: state => state.user !== null,
58 | })
59 |
60 | const userIsAuthenticated = connectedReduxRedirect({
61 | redirectPath: 'unprotected',
62 | authenticatedSelector: state => state.user !== null,
63 | })
64 |
65 | const onEnterAdmin = createOnEnter({
66 | redirectPath: 'home',
67 | authenticatedSelector: state => state.user.isAdmin === false,
68 | })
69 |
70 | const userIsAdmin = connectedReduxRedirect({
71 | redirectPath: 'home',
72 | authenticatedSelector: state => state.user.isAdmin === false,
73 | })
74 |
75 | const getRoutes = (store) => {
76 | const connect = (fn) => (nextState, replaceState) => fn(store, nextState, replaceState);
77 |
78 | //This executes the parent onEnter first, going from left to right.
79 | // `replace` has to be wrapped because we want to stop executing `onEnter` hooks
80 | // after the first call to `replace`.
81 | const onEnterChain = (...listOfOnEnters) => (store, nextState, replace) => {
82 | let redirected = false;
83 | const wrappedReplace = (...args) => {
84 | replace(...args);
85 | redirected = true;
86 | };
87 | listOfOnEnters.forEach((onEnter) => {
88 | if (!redirected) {
89 | onEnter(store, nextState, wrappedReplace);
90 | }
91 | });
92 | };
93 |
94 | return (
95 |
96 |
97 |
98 |
101 |
104 |
105 |
106 | );
107 | };
108 |
109 | ```
110 |
--------------------------------------------------------------------------------
/docs/AdvancedUsage/Redux.md:
--------------------------------------------------------------------------------
1 | # Redux Advanced Usage
2 |
3 | ## Dispatching an Additional Redux Action on Redirect
4 | You may want to dispatch an additional redux action when a redirect occurs. One example of this is to display a notification message
5 | that the user is being redirected or doesn't have access to that protected resource. To do this, you can chain the `redirectAction`
6 | parameter using `redux-thunk` middleware. It depends slightly on if you are using a redux + routing solution or just React Router.
7 |
8 | **Note:** make sure you add `redux-thunk` to your store's middleware or else the following will not work
9 |
10 | #### Using `react-router-redux` or `redux-router` and dispatching an extra redux action in the wrapper
11 | ```js
12 | import { replace } from 'react-router-redux'; // Or your redux-router equivalent
13 | import { connectedReduxRedirect } from 'redux-auth-wrapper/history3/redirect'
14 | import addNotification from './notificationActions';
15 |
16 | // Admin Authorization, redirects non-admins to /app
17 | export const userIsAdmin = connectedReduxRedirect({
18 | redirectPath: '/app',
19 | allowRedirectBack: false,
20 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
21 | redirectAction: (newLoc) => (dispatch) => {
22 | dispatch(replace(newLoc));
23 | dispatch(addNotification({ message: 'Sorry, you are not an administrator' }));
24 | },
25 | wrapperDisplayName: 'UserIsAdmin'
26 | })
27 | ```
28 |
29 | #### Using React Router with history singleton and extra redux action
30 | ```js
31 | import { browserHistory } from 'react-router'; // react router 3
32 | import addNotification from './notificationActions';
33 |
34 | // Admin Authorization, redirects non-admins to /app
35 | export const userIsAdmin = connectedReduxRedirect({
36 | redirectPath: '/app',
37 | allowRedirectBack: false,
38 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
39 | redirectAction: (newLoc) => (dispatch) => {
40 | browserHistory.replace(newLoc);
41 | dispatch(addNotification({ message: 'Sorry, you are not an administrator' }));
42 | },
43 | wrapperDisplayName: 'UserIsAdmin'
44 | })
45 | ```
46 |
--------------------------------------------------------------------------------
/docs/Getting-Started/HidingAlternate.md:
--------------------------------------------------------------------------------
1 | # Hiding and Displaying Alternate Components
2 |
3 | In addition to controlling what pages users can access in an application, another common requirement is to hide or display different elements on the page depending on the user's permissions. redux-auth-wrapper also provides an HOC that makes this easy to do in your application.
4 |
5 | ## Hiding a Component
6 |
7 | If you want to hide a component, you can import the `connectedAuthWrapper` HOC. When the `authenticatedSelector` returns true, the wrapped component will be rendered and passed all props from the parent. When the `authenticatedSelector` returns false, no component will be rendered.
8 |
9 | Here is an example that hides a link from a non-admin user.
10 | ```js
11 | import connectedAuthWrapper from 'redux-auth-wrapper/connectedAuthWrapper'
12 |
13 | const visibleOnlyAdmin = connectedAuthWrapper({
14 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
15 | wrapperDisplayName: 'VisibleOnlyAdmin',
16 | })
17 |
18 | // Applying to a function component for simplicity but could be Class or createClass component
19 | const AdminOnlyLink = visibleOnlyAdmin(() => Admin Section)
20 | ```
21 |
22 | ## Displaying an Alternate Component
23 |
24 | You can also display a component when the `authenticatedSelector` returns false. Simply pass the `FailureComponent` property to the `authWrapper`.
25 |
26 | ```js
27 | import connectedAuthWrapper from 'redux-auth-wrapper/connectedAuthWrapper'
28 |
29 | const visibleOnlyAdmin = connectedAuthWrapper({
30 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
31 | wrapperDisplayName: 'AdminOrHomeLink',
32 | FailureComponent: () => Home Section
33 | })
34 |
35 | // Applying to a function component for simplicity but could be Class or createClass component
36 | const AdminOnlyLink = visibleOnlyAdmin(() => Admin Section)
37 | ```
38 |
39 | You can also easily wrap the call to `authWrapper` in a function to make it more flexible to apply throughout your code:
40 |
41 | ```js
42 | const adminOrElse = (Component, FailureComponent) => connectedAuthWrapper({
43 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
44 | wrapperDisplayName: 'AdminOrElse',
45 | FailureComponent
46 | })(Component)
47 |
48 | // Show Admin dashboard to admins and user dashboard to regular users
49 |
50 | ```
51 |
52 | ## Unconnected Wrapper
53 |
54 | If you don't want to have redux-auth-wrapper connect your selector automatically for you, you can use the un-connected version. This might be useful if you are already connecting the component and dont want the extra overhead of another `connect`, or want to pass the props in via traditional state.
55 |
56 | ```js
57 | import authWrapper from 'redux-auth-wrapper/authWrapper'
58 |
59 | const visibleOnlyAdmin = authWrapper({
60 | wrapperDisplayName: 'VisibleOnlyAdmin',
61 | })
62 |
63 | // Applying to a function component for simplicity but could be Class or createClass component
64 | const AdminOnlyLink = visibleOnlyAdmin(() => Admin Section)
65 |
66 | class MyComponent extends Component {
67 |
68 | ...
69 |
70 | render() {
71 |
72 |
73 |
74 | }
75 |
76 | }
77 | ```
78 |
--------------------------------------------------------------------------------
/docs/Getting-Started/NestingWrappers.md:
--------------------------------------------------------------------------------
1 | # Nesting Wrappers
2 |
3 | Both the redirection HOCs and `authWrapper` can be nested (composed) together to create additional constraints for auth. This is especially useful when you want to provide authorization checks, such as checking a user is logged in and also an administrator.
4 |
5 | For example, we can create a button that will only display for logged in users named Bob:
6 |
7 | ```js
8 | const onlyBob = authWrapper({
9 | authenticatedSelector: state => state.user.firstName === 'Bob'
10 | wrapperDisplayName: 'UserIsOnlyBob',
11 | })
12 |
13 | const OnlyBobButton = onlyBob(MyButton)
14 | ```
15 |
16 | When nesting redirection HOCs, it is important to pay attention to the order of the nesting, especially if you are using a different `redirectPath` or `allowRedirectBack`. Consider the following:
17 |
18 | ``` js
19 | const userIsAuthenticated = connectedRouterRedirect({
20 | redirectPath: '/login',
21 | authenticatedSelector: state => state.user !== null,
22 | wrapperDisplayName: 'UserIsAuthenticated'
23 | })
24 |
25 | const userIsAdmin = connectedRouterRedirect({
26 | authenticatedSelector: state => state.user.isAdmin,
27 | redirectPath: '/app',
28 | wrapperDisplayName: 'UserIsAdmin',
29 | allowRedirectBack: false
30 | })
31 |
32 | // Now to secure the component: first check if the user is authenticated, and then check if the user is an admin
33 |
34 | ```
35 |
36 | Because the `userIsAuthenticated` check happens first, if the users aren't logged in they will be sent to the `/login` first, skipping the admin check all together. Then once they've authenticated, they can be checked for if they are an admin. Otherwise, they would be sent to `/app` which might also be protected by a `userIsAuthenticated` and then get sent to `/login` from there (assuming another auth check). This would result in the user ending up at `/app` once they've authenticated, instead of at `/admin` if they are an admin but weren't logged in at the time.
37 |
38 | #### Chaining using compose
39 |
40 | Since Higher Order Components are functions, they can easily be chained together using `compose` to prevent accidentally applying them in the wrong order. `compose` can be imported from redux, or recompose:
41 |
42 | ```js
43 | import { compose } from 'redux'
44 |
45 | // userIsAuthenticated and userIsAdmin from above
46 | const userIsAdminChain = compose(userIsAuthenticated, userIsAdmin)
47 |
48 | // Now to secure the component, you don't have to think which order to apply!
49 |
50 | ```
51 |
--------------------------------------------------------------------------------
/docs/Getting-Started/Overview.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | ## Higher Order Components
4 |
5 | redux-auth-wrapper makes use of higher order components to decouple the rendering logic in your components from the permissions a user might have. If you are unfamiliar with using higher order components or where to apply them, please read below, otherwise skip to the [Tutorials](#tutorials).
6 |
7 | For a great read on what higher order components are, check out Dan Abramov's blog post:
8 |
9 | [Higher Order Components](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750#.ao9jjxx89).
10 | > A higher-order component is just a function that takes an existing component and returns another component that wraps it
11 |
12 | ### Where to apply
13 |
14 | Higher order components are extremely powerful tools for adding logic to your components and keeping them easy to understand. It is important, however, to apply HOCs in the proper place. Failure to do so can cause subtle bugs and performance problems in your code.
15 |
16 | In all of the following examples, we use the hoc `authWrapper`, but this advice applies for all HOCs (even ones not from redux-auth-wrapper).
17 |
18 | #### Safe to Apply
19 |
20 | Directly inside ReactDOM.render:
21 | ```js
22 | ReactDOM.render(
23 |
24 |
25 |
26 |
27 | ...
28 |
29 |
30 | ,
31 | document.getElementById('mount')
32 | )
33 | ```
34 |
35 | Separate route config file:
36 | ```js
37 | const routes = (
38 |
39 |
40 | ...
41 |
42 | )
43 |
44 | ReactDOM.render(
45 |
46 |
47 | {routes}
48 |
49 | ,
50 | document.getElementById('mount')
51 | )
52 | ```
53 |
54 | Applied in the component file (es7):
55 | ```js
56 | @authWrapper
57 | export default class MyComponent extends Component {
58 | ...
59 | }
60 | ```
61 |
62 | Applied in the component file (es6):
63 | ```js
64 | class MyComponent extends Component {
65 | ...
66 | }
67 | export default UserIsAuthenticated(MyComponent)
68 | ```
69 |
70 | Applied outside the component file:
71 | ```js
72 | import MyComponent from './component/mycomponent.js'
73 |
74 | const MyAuthComponent = authWrapper(MyComponent)
75 | ```
76 |
77 | #### Not Safe to Apply
78 |
79 | The following are all not safe because they create a new component over and over again, preventing react from considering these the "same" component and causing mounting/unmounting loops.
80 |
81 | Inside of render:
82 | ```js
83 | import MyComponent from './component/MyComponent.js'
84 |
85 | class MyParentComponent extends Component {
86 | render() {
87 | const MyAuthComponent = authWrapper(MyComponent)
88 | return
89 | }
90 | }
91 | ```
92 |
93 | Inside of any `getComponent` (react router 3):
94 | ```js
95 | const routes = (
96 |
97 | {
98 | cb(null, authWrapper(Foo))
99 | }} />
100 | ...
101 |
102 | )
103 | ```
104 |
105 | ## Tutorials
106 |
107 | * [React Router 3 Tutorial](ReactRouter3.md)
108 | * [React Router 4 Tutorial](ReactRouter4.md)
109 | * [React Native Tutorial](ReactNative.md)
110 | * [Hiding and Alternative Components](HidingAlternate.md)
111 | * [Nesting Wrappers](NestingWrappers.md)
112 |
--------------------------------------------------------------------------------
/docs/Getting-Started/ReactNative.md:
--------------------------------------------------------------------------------
1 | # React Native Redirection
2 |
3 | Using redux-auth-wrapper with React Native? Please help improve these docs and the examples by submitting a Pull Request!
4 |
--------------------------------------------------------------------------------
/docs/Getting-Started/ReactRouter3.md:
--------------------------------------------------------------------------------
1 | # React Router 3 Redirection
2 |
3 | At first glance, it appears that redux-auth-wrapper is unnecessary in React Router 3 because of the [onEnter](https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#onenternextstate-replace-callback) method.
4 |
5 | `onEnter` is great, and useful in certain situations. However, here are some common auth problems `onEnter` does not solve:
6 | * Decide authentication/authorization from redux store data (there are some [workarounds](https://github.com/CrocoDillon/universal-react-redux-boilerplate/blob/master/src/routes.js#L8))
7 | * Recheck auth when the store changes but not the current route (not possible!)
8 |
9 | Instead, we can use redux-auth-wrapper to protect React Router 3 routes with auth checks to more easily interact with our redux store.
10 |
11 | ## Securing a Route
12 |
13 | To add redirection to your app with React Router 3, import the following helper:
14 | ```js
15 | import { connectedRouterRedirect } from 'redux-auth-wrapper/history3/redirect'
16 | ```
17 |
18 | The `connectedRouterRedirect` will build the redirect higher order component, but we have to first pass in a config object. The wrapper needs to know how to determine if a user is allowed to access the route.
19 |
20 | ```js
21 | const userIsAuthenticated = connectedRouterRedirect({
22 | // The url to redirect user to if they fail
23 | redirectPath: '/login',
24 | // Determine if the user is authenticated or not
25 | authenticatedSelector: state => state.user !== null,
26 | // A nice display name for this check
27 | wrapperDisplayName: 'UserIsAuthenticated'
28 | })
29 | ```
30 |
31 | `userIsAuthenticated` is a Higher Order Component, so we can apply it to the component we want to protect. You can do this in many places, see [where to apply the wrappers](Overview.md#where-to-apply) for more details. In our case, we apply it directly in the route definition.
32 |
33 | ```js
34 |
35 | ```
36 |
37 | When the user navigates to `/profile`, one of the following occurs:
38 |
39 | 1. If The `state.user` is null:
40 |
41 | The user is redirected to `/login?redirect=%2Fprofile`
42 |
43 | *Notice the url contains the query parameter `redirect` for sending the user back to after you log them into your app*
44 | 2. Otherwise:
45 |
46 | The `` component is rendered
47 |
48 | ## Redirecting from Login
49 |
50 | We've only done half of the work however. When a user logs into the login page, we want to send them back to `/profile`. Additionally, if a user is already logged in, but navigates to our login page, we may want to send them to a landing page (`/landing`). Luckily we can easily do both of these with another wrapper.
51 |
52 | ```js
53 | import locationHelperBuilder from 'redux-auth-wrapper/history3/locationHelper'
54 |
55 | const locationHelper = locationHelperBuilder({})
56 |
57 | const userIsNotAuthenticated = connectedRouterRedirect({
58 | // This sends the user either to the query param route if we have one, or to the landing page if none is specified and the user is already logged in
59 | redirectPath: (state, ownProps) => locationHelper.getRedirectQueryParam(ownProps) || '/landing',
60 | // This prevents us from adding the query parameter when we send the user away from the login page
61 | allowRedirectBack: false,
62 | // Determine if the user is authenticated or not
63 | authenticatedSelector: state => state.user === null,
64 | // A nice display name for this check
65 | wrapperDisplayName: 'UserIsNotAuthenticated'
66 | })
67 | ```
68 |
69 | ```js
70 |
71 |
72 | ```
73 |
74 | The `locationHelper` requires the `location` object in props. If the component is not rendered as part of a route component then you must use the `withRouter` HOC from `react-router`:
75 |
76 | ```js
77 | withRouter(userIsNotAuthenticated(Login))
78 | ```
79 |
80 | ## Displaying an AuthenticatingComponent Component
81 |
82 | Its often useful to display some sort of loading component or animation when you are checking if the user's credentials are valid or if the user is already logged in. We can add a loading component to both our Login and Profile page easily:
83 |
84 | When `authenticatingSelector` returns true, no redirection will be performed and the the specified `AuthenticatingComponent` will be displayed. If no `AuthenticatingComponent` is specified, then no component will be rendered (null).
85 |
86 | ```js
87 | const userIsAuthenticated = connectedRouterRedirect({
88 | redirectPath: '/login',
89 | authenticatedSelector: state => state.user !== null,
90 | wrapperDisplayName: 'UserIsAuthenticated'
91 | // Returns true if the user auth state is loading
92 | authenticatingSelector: state => state.user.isLoading,
93 | // Render this component when the authenticatingSelector returns true
94 | AuthenticatingComponent: LoadingSpinner,
95 | })
96 | ```
97 |
98 | You can also add an `authenticatingSelector` and `AuthenticatingComponent`
99 |
100 | ## Integrating with redux-based routing
101 |
102 | If you want to dispatch a redux action to perform navigation instead of interacting directly with the history/router object then you can pass the redux action creator to `redirectAction`. Note that using `redirectAction` is not required if you use redux-based or redux-integrated routing, it only changes how the route change is triggered in the client.
103 |
104 | To do this, swap out the import of `connectedRouterRedirect` for `connectedReduxRedirect` and pass the `redirectAction` parameter to the config object:
105 |
106 | ```js
107 | import { connectedReduxRedirect } from 'redux-auth-wrapper/history3/redirect'
108 | import { routerActions } from 'react-router-redux'
109 |
110 | const userIsAuthenticated = connectedReduxRedirect({
111 | redirectPath: '/login',
112 | authenticatedSelector: state => state.user !== null,
113 | wrapperDisplayName: 'UserIsAuthenticated',
114 | // This should be a redux action creator
115 | redirectAction: routerActions.replace,
116 | })
117 | ```
118 |
119 | ## Next Steps
120 |
121 | Check out the [examples](https://github.com/mjrussell/redux-auth-wrapper/tree/master/examples) or browse the [API documentation](/docs/API.md). If you are using server side rendering (SSR) with React Router 3, you should also check out the [Server Side Rendering](/docs/AdvancedUsage/ReactRouter3.md) documentation.
122 |
--------------------------------------------------------------------------------
/docs/Getting-Started/ReactRouter4.md:
--------------------------------------------------------------------------------
1 | # React Router 4/5 Redirection
2 |
3 | _note: this guide refers mainlys to React Router 4. React Router 5 is the same API and redux-auth-wrapper 3.x is fully compatible with React Router 5._
4 |
5 | React Router 4 removed `onEnter` and `onChange` in favor of performing those routing logic actions inside component life cycle methods. This is what redux-auth-wrapper already does with Higher Order Components!
6 |
7 | Using redux-auth-wrapper with React Router 4 is very similar to React Router 3 with a few changes.
8 |
9 | ## Securing a Route
10 |
11 | To add redirection to your app with React Router 4, import the following helper:
12 | ```js
13 | import { connectedRouterRedirect } from 'redux-auth-wrapper/history4/redirect'
14 | ```
15 |
16 | The `connectedRouterRedirect` will build the redirect higher order component, but we have to first pass in a config object. The wrapper needs to know how to determine if a user is allowed to access the route.
17 |
18 | ```js
19 | const userIsAuthenticated = connectedRouterRedirect({
20 | // The url to redirect user to if they fail
21 | redirectPath: '/login',
22 | // If selector is true, wrapper will not redirect
23 | // For example let's check that state contains user data
24 | authenticatedSelector: state => state.user.data !== null,
25 | // A nice display name for this check
26 | wrapperDisplayName: 'UserIsAuthenticated'
27 | })
28 | ```
29 |
30 | `userIsAuthenticated` is a Higher Order Component, so we can apply it to the component we want to protect. You can do this in many places, see [where to apply the wrappers](Overview.md#where-to-apply) for more details. In our case, we apply it directly in the route definition.
31 |
32 | ```js
33 |
34 | ```
35 |
36 | When the user navigates to `/profile`, one of the following occurs:
37 |
38 | 1. If The `state.user` is null:
39 |
40 | The user is redirected to `/login?redirect=%2Fprofile`
41 |
42 | *Notice the url contains the query parameter `redirect` for sending the user back to after you log them into your app*
43 | 2. Otherwise:
44 |
45 | The `` component is rendered
46 |
47 | ## Redirecting from Login
48 |
49 | We've only done half of the work however. When a user logs into the login page, we want to send them back to `/profile`. Additionally, if a user is already logged in, but navigates to our login page, we may want to send them to a landing page (`/landing`). Luckily we can easily do both of these with another wrapper.
50 |
51 | ```js
52 | import locationHelperBuilder from 'redux-auth-wrapper/history4/locationHelper'
53 |
54 | const locationHelper = locationHelperBuilder({})
55 |
56 | const userIsNotAuthenticated = connectedRouterRedirect({
57 | // This sends the user either to the query param route if we have one, or to the landing page if none is specified and the user is already logged in
58 | redirectPath: (state, ownProps) => locationHelper.getRedirectQueryParam(ownProps) || '/landing',
59 | // This prevents us from adding the query parameter when we send the user away from the login page
60 | allowRedirectBack: false,
61 | // If selector is true, wrapper will not redirect
62 | // So if there is no user data, then we show the page
63 | authenticatedSelector: state => state.user.data === null,
64 | // A nice display name for this check
65 | wrapperDisplayName: 'UserIsNotAuthenticated'
66 | })
67 | ```
68 |
69 | ```js
70 |
71 |
72 | ```
73 |
74 | The `locationHelper` requires the `location` object in props. If the component is not rendered as part of a route component then you must use the `withRouter` HOC from `react-router`:
75 |
76 | ```js
77 | withRouter(userIsNotAuthenticated(Login))
78 | ```
79 |
80 | ## Displaying an AuthenticatingComponent Component
81 |
82 | Its often useful to display some sort of loading component or animation when you are checking if the user's credentials are valid or if the user is already logged in. We can add a loading component to both our Login and Profile page easily:
83 |
84 | When `authenticatingSelector` returns true, no redirection will be performed and the the specified `AuthenticatingComponent` will be displayed. If no `AuthenticatingComponent` is specified, then no component will be rendered (null).
85 |
86 | ```js
87 | const userIsAuthenticated = connectedRouterRedirect({
88 | redirectPath: '/login',
89 | authenticatedSelector: state => state.user.data !== null,
90 | wrapperDisplayName: 'UserIsAuthenticated',
91 | // Returns true if the user auth state is loading
92 | authenticatingSelector: state => state.user.isLoading,
93 | // Render this component when the authenticatingSelector returns true
94 | AuthenticatingComponent: LoadingSpinner
95 | })
96 | ```
97 |
98 | You can also add an `authenticatingSelector` and `AuthenticatingComponent`
99 |
100 | ## Integrating with redux-based routing
101 |
102 | If you want to dispatch a redux action to perform navigation instead of interacting directly with the history/router object then you can pass the redux action creator to `redirectAction`. Note that using `redirectAction` is not required if you use redux-based or redux-integrated routing, it only changes how the route change is triggered in the client.
103 |
104 | To do this, swap out the import of `connectedRouterRedirect` for `connectedReduxRedirect` and pass the `redirectAction` parameter to the config object:
105 |
106 | ```js
107 | import { connectedReduxRedirect } from 'redux-auth-wrapper/history4/redirect'
108 | import { replace } from 'connected-react-router'
109 |
110 | const userIsAuthenticated = connectedReduxRedirect({
111 | redirectPath: '/login',
112 | authenticatedSelector: state => state.user !== null,
113 | wrapperDisplayName: 'UserIsAuthenticated',
114 | // This should be a redux action creator
115 | redirectAction: replace,
116 | })
117 | ```
118 |
119 | ## Next Steps
120 |
121 | Check out the [examples](https://github.com/mjrussell/redux-auth-wrapper/tree/master/examples) or browse the [API documentation](/docs/API.md).
122 |
--------------------------------------------------------------------------------
/docs/Migrating.md:
--------------------------------------------------------------------------------
1 | # Migrating from Version 1.x to Version 2.x
2 |
3 | ## Motivation for 2.x
4 |
5 | redux-auth-wrapper has really changed a lot since it was first designed as a small specialized utility for handling redirection with react-router-redux. Since then, it has been adopted by many developers and they've used it in numerous unforeseen and useful ways such as hiding components, displaying alternate components, and integrating with other routers. Additionally, redux-auth-wrapper needed to support two version of React Router (3 and 4) which had very different APIs. Therefore, version 2.x breaks redux-auth-wrapper into many more small, composable pieces. redux-auth-wrapper still provides a simple import for those looking to get started quickly with React Router, but also allows for developers to import the building blocks to create redirection wrappers that work with any router (or history directly). You can even use redux-auth-wrapper 2.x in a project without redux or even routing.
6 |
7 | The largest change is that wrappers that perform redirection have been split from those that hide or display alternate components using `FailureComponent`.
8 | This made practical sense since using a FailureComponent disabled the redirection, yet the wrapper would still complain
9 | about missing redirection helpers like `history` even when they would not be used. Now you can use Failure Component wrappers
10 | without even a router.
11 |
12 | ## Migrating redirection wrappers
13 |
14 | The main changes are the following:
15 | * Combined `authSelector` and `predicate` into a single `authenticatedSelector`
16 | * No longer passed `authData` as a prop to child components. This was the return value of `authSelector`. If you need your auth data, just connect it at a lower level.
17 | * renamed `LoadingComponent` to `AuthenticatingComponent`
18 | * renamed `failureRedirectPath` to `redirectPath`
19 | * `redirectPath` no longer defaults to `/login`
20 | * removed `FailureComponent` from the redirect helper, see [Migrating failure and alternative components](#migrating-failure-and-alternative-components) for details
21 | * Removed `mapProps`. If you need to prevent passing down any props from redux-auth-wrapper, use `mapProps` from recompose.
22 |
23 | Previously:
24 |
25 | v1.x:
26 | ```js
27 | import { UserAuthWrapper } from 'redux-auth-wrapper'
28 |
29 | const UserIsAuthenticated = UserAuthWrapper({
30 | authSelector: state => state.user.data,
31 | authenticatingSelector: state => state.user.isLoading,
32 | LoadingComponent: Loading,
33 | redirectAction: routerActions.replace,
34 | wrapperDisplayName: 'UserIsAuthenticated'
35 | })
36 | ```
37 |
38 | v2.x:
39 | ```js
40 | // NOTE: use history3 because coming from React Router 2/3. If planning to upgrade to React Router 4 use history4
41 | import { connectedReduxRedirect } from 'redux-auth-wrapper/history3/redirect'
42 |
43 | export const userIsAuthenticated = connectedReduxRedirect({
44 | redirectPath: '/login',
45 | authenticatedSelector: state => state.user.data !== null,
46 | authenticatingSelector: state => state.user.isLoading,
47 | AuthenticatingComponent: Loading,
48 | redirectAction: routerActions.replace,
49 | wrapperDisplayName: 'UserIsAuthenticated'
50 | })
51 | ```
52 |
53 | **Note:** If not using `redirectAction`, import `connectedRouterRedirect` instead.
54 |
55 | ## Migrating failure and alternative components
56 |
57 | * Combined `authSelector` and `predicate` into a single `authenticatedSelector`
58 | * FailureComponent is optional now, not specifying it will render nothing (null) when the `authenticatedSelector` returns false
59 | * All properties besides `authenticatedSelector`, `authenticatingSelector`, `FailureComponent`, and `wrapperDisplayName` have been removed
60 |
61 | ### Hiding Components
62 |
63 | v1.x
64 | ```js
65 | import { UserAuthWrapper } from 'redux-auth-wrapper'
66 |
67 |
68 | const VisibleOnlyAdmin = UserAuthWrapper({
69 | authSelector: state => state.user,
70 | wrapperDisplayName: 'VisibleOnlyAdmin',
71 | predicate: user => user.isAdmin,
72 | FailureComponent: null
73 | })
74 |
75 | // Applying to a function component for simplicity but could be Class or createClass component
76 | const AdminOnlyLink = VisibleOnlyAdmin(() => Admin Section)
77 | ```
78 |
79 | v2.x
80 | ```js
81 | import connectedAuthWrapper from 'redux-auth-wrapper/connectedAuthWrapper'
82 |
83 | const visibleOnlyAdmin = authWrapper({
84 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
85 | wrapperDisplayName: 'VisibleOnlyAdmin',
86 | })
87 | ```
88 |
89 | ### Alternate Components
90 |
91 | v1.x
92 | ```js
93 | import { UserAuthWrapper } from 'redux-auth-wrapper'
94 |
95 | const AdminOrElse = (Component, FailureComponent) => UserAuthWrapper({
96 | authSelector: state => state.user,
97 | wrapperDisplayName: 'AdminOrElse',
98 | predicate: user => user.isAdmin,
99 | FailureComponent
100 | })(Component)
101 |
102 | // Show Admin dashboard to admins and user dashboard to regular users
103 |
104 | ```
105 |
106 | v2.x
107 | ```js
108 | import connectedAuthWrapper from 'redux-auth-wrapper/connectedAuthWrapper'
109 |
110 | const adminOrElse = (Component, FailureComponent) => connectedAuthWrapper({
111 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
112 | wrapperDisplayName: 'AdminOrElse',
113 | FailureComponent
114 | })(Component)
115 |
116 | // Show Admin dashboard to admins and user dashboard to regular users
117 |
118 | ```
119 |
--------------------------------------------------------------------------------
/docs/Troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting and Common Issues
2 |
3 | Having trouble with redux-auth-wrapper? Check out the following common issues.
4 |
5 | #### Applying the HOC
6 |
7 | Make sure that when using the helpers from redux-auth-wrapper that you are applying the HOC to your component and in the right location (see [where to apply the wrappers](Overview.md#where-to-apply) for more details). Most imports from this library are HOC builders, requiring first a configuration object. For instance you shouldn't be applying the `connectedRouterRedirect` directly to a component:
8 |
9 | Incorrect:
10 | ```js
11 | const ProtectedComponent = connectedRouterRedirect(MyComponent)
12 | ```
13 |
14 | Correct:
15 | ```js
16 | const userIsAuthenticated = connectedRouterRedirect({
17 | redirectPath: '/login',
18 | authenticatedSelector: state => state.user !== null
19 | })
20 |
21 | const ProtectedComponent = userIsAuthenticated(MyComponent)
22 | ```
23 |
24 | Also, please be sure that you've applied the HOC in a proper location. Check out the documentation on [where to apply auth wrappers](/docs/Getting-Started/Overview.md#where-to-apply).
25 |
26 | #### Rendering the wrapped component
27 |
28 | Also remember that the result of an HOC being applied to a Component is a new Component, so you cannot render it without instantiating it:
29 |
30 | Incorrect:
31 | ```js
32 | const visibleOnlyAdmin = authWrapper({
33 | authenticatedSelector: state => state.user !== null && state.user.isAdmin,
34 | wrapperDisplayName: 'AdminOrHomeLink',
35 | FailureComponent: () => Home Section
36 | })
37 |
38 | const AdminOnlyLink = visibleOnlyAdmin(() => Admin Section)
39 |
40 | class MyComponent extends Component {
41 | render() {
42 | return (
43 |