├── travis.yml ├── .npmignore ├── src ├── types │ ├── authTypes.ts │ └── userTypes.ts ├── store.ts ├── actions │ ├── authActions.ts │ └── userActions.ts ├── reducers │ ├── authReducer.ts │ └── userReducer.ts ├── hoc │ ├── user.tsx │ ├── auth.tsx │ └── guard.tsx └── index.ts ├── .gitignore ├── tsconfig.json ├── package.json ├── LICENSE └── README.md /travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 8 5 | 6 | script: 7 | - npm run build -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | /src 3 | /node_modules 4 | .idea 5 | .DS_Store 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | -------------------------------------------------------------------------------- /src/types/authTypes.ts: -------------------------------------------------------------------------------- 1 | export const LOGIN_START = 'AUTH_LOGIN_START'; 2 | export const LOGIN_END = 'AUTH_LOGIN_END'; 3 | export const LOGOUT_START = 'AUTH_LOGOUT_START'; 4 | export const LOGOUT_END = 'AUTH_LOGOUT_END'; -------------------------------------------------------------------------------- /src/types/userTypes.ts: -------------------------------------------------------------------------------- 1 | export const RESET = 'USER_RESET'; 2 | export const FETCH_SUCCESS = 'USER_FETCH_SUCCESS'; 3 | export const FETCH_START = 'USER_FETCH_START'; 4 | export const FETCH_END = 'USER_FETCH_END'; 5 | export const FETCH_ERROR = 'USER_FETCH_ERROR'; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # production 7 | /dist 8 | 9 | # misc 10 | .idea 11 | .DS_Store 12 | 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | package-lock.json 18 | -------------------------------------------------------------------------------- /src/store.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers, createStore } from "redux"; 2 | import userReducer from './reducers/userReducer'; 3 | import authReducer from './reducers/authReducer'; 4 | 5 | export default () => createStore( 6 | combineReducers({ 7 | user: userReducer, 8 | auth: authReducer 9 | }) 10 | ); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "sourceMap": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es6", 11 | "outDir": "dist", 12 | "baseUrl": ".", 13 | "jsx": "react" 14 | } 15 | } -------------------------------------------------------------------------------- /src/actions/authActions.ts: -------------------------------------------------------------------------------- 1 | import * as types from '../types/authTypes'; 2 | 3 | export const loginStart = () => ({ 4 | type: types.LOGIN_START 5 | }); 6 | 7 | export const loginEnd = () => ({ 8 | type: types.LOGIN_END 9 | }); 10 | 11 | export const logoutStart = () => ({ 12 | type: types.LOGOUT_START 13 | }); 14 | 15 | export const logoutEnd = () => ({ 16 | type: types.LOGOUT_END 17 | }); -------------------------------------------------------------------------------- /src/actions/userActions.ts: -------------------------------------------------------------------------------- 1 | import * as types from '../types/userTypes'; 2 | 3 | export const reset = () => ({ 4 | type: types.RESET 5 | }); 6 | 7 | export const fetchStart = () => ({ 8 | type: types.FETCH_START 9 | }); 10 | 11 | export const fetchEnd = () => ({ 12 | type: types.FETCH_END 13 | }); 14 | 15 | export const fetchError = () => ({ 16 | type: types.FETCH_ERROR 17 | }); 18 | 19 | export const fetchSuccess = data => ({ 20 | type: types.FETCH_SUCCESS, 21 | payload: data 22 | }); 23 | -------------------------------------------------------------------------------- /src/reducers/authReducer.ts: -------------------------------------------------------------------------------- 1 | import * as types from '../types/authTypes'; 2 | 3 | const initialState = { 4 | loading: false 5 | }; 6 | 7 | const userReducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case types.LOGIN_START: 10 | case types.LOGOUT_START: 11 | return { 12 | ...state, 13 | loading: true 14 | }; 15 | case types.LOGIN_END: 16 | case types.LOGOUT_END: 17 | return { 18 | ...state, 19 | loading: false 20 | }; 21 | default: 22 | return state; 23 | } 24 | } 25 | 26 | export default userReducer; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-authmanager", 3 | "version": "2.0.4", 4 | "description": "...", 5 | "main": "dist/index.js", 6 | "author": "hello@pierrecabriere.fr", 7 | "license": "MIT", 8 | "scripts": { 9 | "build": "tsc", 10 | "build:watch": "tsc -w" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/pierrecabriere/react-authmanager.git" 15 | }, 16 | "homepage": "https://github.com/pierrecabriere/react-authmanager#readme", 17 | "keywords": [ 18 | "authentication", 19 | "JWT", 20 | "react", 21 | "redux", 22 | "user", 23 | "guard" 24 | ], 25 | "dependencies": { 26 | "hoc-manager": "^1.1.0", 27 | "react": "^16.13.1", 28 | "redux": "^4.0.5" 29 | }, 30 | "devDependencies": { 31 | "typescript": "^3.8.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/reducers/userReducer.ts: -------------------------------------------------------------------------------- 1 | import * as types from '../types/userTypes'; 2 | 3 | const initialState = { 4 | loading: false, 5 | logged: false, 6 | user: null 7 | }; 8 | 9 | const userReducer = (state = initialState, action) => { 10 | switch (action.type) { 11 | case types.FETCH_START: 12 | return { 13 | ...state, 14 | loading: true 15 | }; 16 | case types.FETCH_END: 17 | return { 18 | ...state, 19 | loading: false 20 | }; 21 | case types.FETCH_ERROR: 22 | case types.RESET: 23 | return initialState; 24 | case types.FETCH_SUCCESS: 25 | return { 26 | ...state, 27 | logged: action.payload.logged, 28 | user: action.payload.user 29 | }; 30 | default: 31 | return state; 32 | } 33 | } 34 | 35 | export default userReducer; -------------------------------------------------------------------------------- /src/hoc/user.tsx: -------------------------------------------------------------------------------- 1 | import HOCManager from "hoc-manager"; 2 | import React from "react"; 3 | 4 | export default instance => HOCManager.create(Component => { 5 | return class WithUser extends React.Component { 6 | props: any; 7 | unsubscribe; 8 | state = {}; 9 | 10 | setState: Function; 11 | 12 | constructor(props) { 13 | super(props); 14 | 15 | this.unsubscribe = instance.store.subscribe(() => { 16 | const { user } = instance.store.getState(); 17 | if (JSON.stringify(this.state) != JSON.stringify(user)) { 18 | this.setState(user); 19 | } 20 | }); 21 | } 22 | 23 | componentWillUnmount() { 24 | this.unsubscribe && this.unsubscribe(); 25 | } 26 | 27 | render() { 28 | const { user } = instance.store.getState(); 29 | return 30 | } 31 | } 32 | }, { 33 | acceptParameters: false 34 | }) 35 | -------------------------------------------------------------------------------- /src/hoc/auth.tsx: -------------------------------------------------------------------------------- 1 | import HOCManager from "hoc-manager"; 2 | import React from "react"; 3 | 4 | export default instance => HOCManager.create(Component => { 5 | return class WithAuth extends React.Component { 6 | props: any; 7 | unsubscribe; 8 | state = {}; 9 | 10 | componentWillMount() { 11 | this.unsubscribe = instance.store.subscribe(() => { 12 | const { auth } = instance.store.getState(); 13 | if (JSON.stringify(this.state) !== JSON.stringify(auth)) { 14 | // @ts-ignore 15 | this.setState(auth); 16 | } 17 | }); 18 | } 19 | 20 | componentWillUnmount() { 21 | this.unsubscribe && this.unsubscribe(); 22 | } 23 | 24 | render() { 25 | const { auth } = instance.store.getState(); 26 | return instance.login(data) } logout={ () => instance.logout() } />; 27 | } 28 | } 29 | }, { 30 | acceptParameters: false 31 | }) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Pierre Cabrière 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/hoc/guard.tsx: -------------------------------------------------------------------------------- 1 | import HOCManager from "hoc-manager"; 2 | import React from "react"; 3 | 4 | export default instance => HOCManager.create((Component, parameters) => { 5 | return class WithGuard extends React.Component { 6 | props: any; 7 | unsubscribe; 8 | state = {}; 9 | 10 | componentDidMount() { 11 | this.unsubscribe = instance.store.subscribe(() => { 12 | const { user } = instance.store.getState(); 13 | if (JSON.stringify(this.state) != JSON.stringify(user)) { 14 | // @ts-ignore 15 | this.setState(user); 16 | } 17 | }); 18 | } 19 | 20 | componentWillUnmount() { 21 | this.unsubscribe && this.unsubscribe(); 22 | } 23 | 24 | render() { 25 | const { user } = instance.store.getState(); 26 | const next: Function = (nextProps = {}) => ; 27 | 28 | let guard = parameters[0]; 29 | if ('string' === typeof guard) { 30 | guard = instance.getGuard(guard); 31 | } 32 | 33 | const render = guard(user, this.props, next); 34 | 35 | return React.isValidElement(render) ? render : "Guard must return a valid react component"; 36 | } 37 | } 38 | }, { 39 | acceptParameters: true 40 | }) 41 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as authActions from "./actions/authActions"; 2 | import * as userActions from "./actions/userActions"; 3 | import AuthHOC from "./hoc/auth"; 4 | import GuardHOC from "./hoc/guard"; 5 | import UserHOC from "./hoc/user"; 6 | import store from "./store"; 7 | 8 | interface IReactAuthConfig { 9 | fetchToken?: Function, 10 | fetchUser?: Function, 11 | isUserLogged?: Function 12 | } 13 | 14 | class ReactAuth { 15 | private static jwtName = 'REACT-AUTH-JWT'; 16 | private static defaultConfig: IReactAuthConfig = { 17 | fetchToken: () => null, 18 | fetchUser: () => null, 19 | isUserLogged: data => !!data && Object.keys(data).length > 0 20 | }; 21 | 22 | private _guards = {}; 23 | 24 | name: string; 25 | config: IReactAuthConfig; 26 | store: any; 27 | 28 | // hoc 29 | withAuth: Function; 30 | withUser: Function; 31 | withGuard: Function; 32 | 33 | constructor(name?: string, config?: IReactAuthConfig) { 34 | const { constructor: { defaultConfig } } = Object.getPrototypeOf(this); 35 | this.config = Object.assign({}, defaultConfig, config); 36 | this.name = name; 37 | this.store = store(); 38 | this.withAuth = AuthHOC(this); 39 | this.withUser = UserHOC(this); 40 | this.withGuard = GuardHOC(this); 41 | 42 | return this; 43 | } 44 | 45 | create(name: string, config: IReactAuthConfig) { 46 | return new ReactAuth(name, config); 47 | } 48 | 49 | get jwtName() { 50 | const { constructor: { jwtName } } = Object.getPrototypeOf(this); 51 | return this.name ? `${ jwtName }_${ this.name }` : jwtName; 52 | } 53 | 54 | getToken() { 55 | return localStorage.getItem(this.jwtName); 56 | } 57 | 58 | setToken(token) { 59 | localStorage.setItem(this.jwtName, token); 60 | return this; 61 | } 62 | 63 | deleteToken() { 64 | localStorage.removeItem(this.jwtName); 65 | return this; 66 | } 67 | 68 | addGuard(name, fn) { 69 | Object.assign(this._guards, { [name]: fn }) 70 | } 71 | 72 | getGuard(name) { 73 | return this._guards[name]; 74 | } 75 | 76 | // helpers 77 | 78 | async login(data) { 79 | this.store.dispatch(authActions.loginStart()); 80 | try { 81 | const token = await this.config.fetchToken(data); 82 | this.setToken(token); 83 | this.store.dispatch(authActions.loginEnd()); 84 | return await this.getUser(); 85 | } catch (e) { 86 | this.store.dispatch(authActions.loginEnd()); 87 | throw e; 88 | } 89 | } 90 | 91 | logout() { 92 | this.store.dispatch(authActions.logoutStart()); 93 | this.store.dispatch(userActions.reset()); 94 | this.deleteToken(); 95 | this.store.dispatch(authActions.logoutEnd()); 96 | return true; 97 | } 98 | 99 | async getUser() { 100 | this.store.dispatch(userActions.fetchStart()); 101 | let user; 102 | try { 103 | user = await this.config.fetchUser(); 104 | const logged = await this.config.isUserLogged(user); 105 | this.store.dispatch(userActions.fetchSuccess({ user, logged })); 106 | this.store.dispatch(userActions.fetchEnd()); 107 | } catch (e) { 108 | this.store.dispatch(userActions.fetchError()); 109 | this.store.dispatch(userActions.fetchEnd()); 110 | throw e; 111 | } 112 | return user; 113 | } 114 | } 115 | 116 | export default new ReactAuth(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React authentication manager 🔑 2 | 3 | [![NPM version](https://img.shields.io/npm/v/react-authmanager.svg)](https://www.npmjs.com/package/react-authmanager) 4 | 5 | **react-authmanager is a highly-configurable manager for react. It manages users authentication with JWT in your app and provides guards HOCs to secure components in a flexible and simple way.** 6 | 7 | --- 8 | 9 | - [Getting started](#1---getting-started) 10 | - [Authenticate users](#2---authenticate-users) 11 | - [Access user informations](#3---access-user-informations) 12 | - [Secure components](#4---secure-components) 13 | - [Authmanager](#5---authmanager) 14 | - [Authmanager.config](#51---authmanagerconfig) 15 | - [Authmanager.utils](#52---authmanager-utils) 16 | 17 | ## 1 - Getting started 18 | `npm install --save react-authmanager`, then you have to configure the package.
19 | To manage configuration, you need to import the default Authmanager.
20 | You need to configure the manager before starting to use, so your highest component file is the best place (by example, it's the `App.js` file with a [create-react-app](https://github.com/facebook/create-react-app) instance !) 21 | 22 | You can also create a new manager instance. 23 | ```js 24 | import Authmanager from 'react-authmanager'; 25 | 26 | const customManager = Authmanager.create("customName", { ...config }); 27 | ``` 28 | 29 | **react-authmanager** needs: 30 | - to know how to login the user from the server and get a token back ([`fetchToken`](#configfetchtokencredentials-async)) 31 | - to know how to get the current logged user informations from the server ([`fetchUser`](#configfetchuser-async)) 32 | 33 | **you** will need: 34 | - to include the current token in your requests headers authorization ([`getToken`](#gettoken)) 35 | 36 | ### Minimal configuration for the manager 37 | ```js 38 | import Authmanager from 'react-authmanager'; 39 | 40 | // how to login the user from the server and get a token back 41 | Authmanager.config.fetchToken = async credentials => { 42 | ... // login user with an ajax call to the server and return the given token 43 | return token; 44 | } 45 | 46 | // how to get the current logged user informations from the server 47 | Authmanager.config.fetchUser = async () => { 48 | ... // get current logged user informations from the server with an ajax call and return any data you will need 49 | return user; 50 | } 51 | ``` 52 | 53 | ### Authorize your requests 54 | ```js 55 | // include the current token in your requests headers authorization 56 | fetch(..., { 57 | headers: new Headers({ 58 | 'Authorization': 'Bearer ' + Authmanager.getToken() // returns null if no token is stored 59 | }), 60 | ... 61 | }); 62 | ``` 63 | 64 | *For more configurations, please read the [Authmanager](#5---authmanager) section below.* 65 | 66 | ## 2 - Authenticate users 67 | **withAuth** HOC injects in your component helpers to manage authentication: **login**, **logout** and **auth**.
68 | **login** and **logout** are functions to log users. **auth** is an object that contains a state of operations. 69 | 70 | | prop | default | description | 71 | |:-----------|:--------|:--------------------------------------------------------------| 72 | | login | | `function` send credentials to the server to get a token back | 73 | | logout | | `function` remove the stored token | 74 | | auth: | | `object` informations about the current state of operations | 75 | | -- loading | false | `bool` is authentication (login or logout) currently loading | 76 | 77 | ```js 78 | import Authmanager from 'react-authmanager'; 79 | 80 | class LoginComponent extends React.Component { 81 | handleSubmit() { 82 | const credentials = { 83 | email: 'hello@example.com', 84 | password: 'ThisIsASecret' 85 | }; // or whatever data you want to send to the server (see the getToken configuration in the Minimal configuration section above) 86 | 87 | this.props.login(credentials) 88 | .then(function() { alert('Hello !') }) 89 | } 90 | 91 | render() { 92 | if (this.props.auth.loading) 93 | return (); 94 | 95 | return ( ... ); 96 | } 97 | 98 | ... 99 | } 100 | 101 | export default Authmanager.withAuth(LoginComponent); // or customManager.withAuth(LoginComponent); 102 | 103 | ... 104 | 105 | class LogoutComponent extends React.Component { 106 | handleClick() { 107 | this.props.logout() 108 | .then(function() { alert('Good bye !') }) 109 | } 110 | 111 | ... 112 | } 113 | 114 | export default Authmanager.withAuth(LogoutComponent); // or customManager.withAuth(LogoutComponent); 115 | ``` 116 | 117 | You can also call the login and logout methods anywhere on the manager with `Authmanager.login()` and `Authmanager.logout()` 118 | 119 | ## 3 - Access user informations 120 | **withUser** HOC will automatically injects an user object in your component props.
121 | This object contains informations about the current user: 122 | 123 | | prop | default | description | 124 | |:-----------|:--------|:--------------------------------------------------------------------------------------------------------| 125 | | user: | | `object` containing current user informations | 126 | | -- loading | false | `bool` is user currently loaded from the server | 127 | | -- logged | false | `bool` is the current user logged in (setted by [`isUserLogged`](#configisuserloggeduser-async)) | 128 | | -- ... | null | `any` informations about the user sent by the server (setted by [`getUser`](#configgetuser-async)) | 129 | 130 | ```js 131 | import Authmanager from 'react-authmanager'; 132 | 133 | class MyComponent extends React.Component { 134 | handleClick() { 135 | if (this.props.user.logged) 136 | alert('Hello ' + this.props.user.name); 137 | else 138 | alert('Hello John, please login !'); 139 | } 140 | 141 | ... 142 | } 143 | 144 | export default Authmanager.withUser(MyComponent); 145 | ``` 146 | 147 | ## 4 - Secure components 148 | **withGuard** HOC helps you protect your components in a flexible way. By example, you can render a login form instead of a component if no user is logged in.
149 | It needs a guard as parameter. A guard is just a function that returns a component, so you can easily create your own guards.
150 | A guard function has parameters: 151 | 152 | | prop | description | 153 | |:------|:---------------------------------------------------------| 154 | | user | `object` the current user object | 155 | | next | `function` a function that returns the current Component | 156 | | props | `object` the current component props | 157 | 158 | ```js 159 | import Authmanager from 'react-authmanager'; 160 | 161 | const loggedGuard = function(user, props, next) { 162 | if (user.loading) 163 | return (); // render a loading component if user is currently fetched from the server 164 | 165 | if (user.logged) 166 | return next(); // render the component if user is not loading and is logged 167 | 168 | return (); // render a login component by default (if user is fetched from the server but not logged) 169 | } 170 | 171 | class MyComponent extends React.Component { 172 | render() { 173 | return ( 174 |
This message is visible only for logged users !
175 | ) 176 | } 177 | 178 | ... 179 | } 180 | 181 | export default Authmanager.withGuard(loggedGuard)(MyComponent); 182 | ``` 183 | 184 | You can inject data in your rendered component props through the next function 185 | ```js 186 | const guardThatInjects = function(user, props, next) { 187 | return next({ myNewProp: true }); 188 | } 189 | 190 | class MyComponent extends React.Component { 191 | render() { 192 | console.log(this.props.myNewProp); // true 193 | return ( 194 |
This message is visible only for logged users !
195 | ) 196 | } 197 | 198 | ... 199 | } 200 | 201 | export default Authmanager.withGuard(loggedGuard)(MyComponent); 202 | ``` 203 | 204 | You can also configure you guards from outside the component file with the [`addGuard`](#addguard) Authmanager function : 205 | 206 | ```js 207 | Authmanager.addGuard('loggedGuard', function(user, props, next) { 208 | if (user.loading) 209 | return (); // render a loading component if user is currently fetched from the server 210 | 211 | if (user.logged) 212 | return next(); // render the component if user is not loading and is logged 213 | 214 | return (); // render a login component by default (if user is fetched from the server but not logged) 215 | }); 216 | 217 | ... 218 | 219 | class MyComponent extends React.Component { 220 | render() { 221 | return ( 222 |
This message is visible only for logged users !
223 | ) 224 | } 225 | 226 | ... 227 | } 228 | 229 | export default Authmanager.withGuard('loggedGuard')(MyComponent); 230 | ``` 231 | 232 | ## 5 - Authmanager 233 | 234 | ### 5.1 - `Authmanager.config` 235 | To edit the configuration of **react-authmanager**your manager, you have to override the config object: 236 | ```js 237 | import Authmanager from 'react-authmanager'; 238 | 239 | // will change the way how the manager will login the user and get a token back, see below 240 | Authmanager.fetchToken = function(credentials) {} 241 | ``` 242 | 243 | ```typescript 244 | interface IReactAuthConfig { 245 | fetchToken?: Function, 246 | fetchUser?: Function, 247 | isUserLogged?: Function 248 | } 249 | ``` 250 | 251 | #### `fetchToken([credentials]) [async]` 252 | Get an authentication token when an user tries to login. `fetchToken` is called when the auth login function is executed to store the token in *localStorage*. 253 | 254 | **Parameters** 255 | - [`credentials`] *(`Object`)* Argument given by the login function. (when you call `Authmanager.login(credentials)`) 256 | 257 | **Return *(`String`)*** 258 | ``` 259 | Need to return a token that will be stored 260 | ``` 261 | 262 | **default** 263 | ```js 264 | fetchToken = null; 265 | ``` 266 | 267 | **example with axios** 268 | ```js 269 | Authmanager.config.fetchToken = async credentials => { 270 | const { data } = await axios.post('https://example.com/login', credentials); 271 | return data.token; 272 | } 273 | ``` 274 | 275 | #### `fetchUser() [async]` 276 | Get the current authenticated user. `fetchUser` is called when the manager initialize its store and after an user login. 277 | 278 | **Return *(`Object`)*** 279 | ``` 280 | Need to return informations about the current logged user 281 | ``` 282 | 283 | **default** 284 | ```js 285 | fetchUser = null; 286 | ``` 287 | 288 | **example with axios** 289 | ```js 290 | Authmanager.config.fetchUser = async () => { 291 | const { data } = await axios.get('https://example.com/current-user'); 292 | return data; 293 | } 294 | ``` 295 | 296 | #### `isUserLogged([user]) [async]` 297 | Define if the current user (returned by `getUser`) is logged. `isUserLogged` is called after each user state change. The result is set in `user.logged`. 298 | 299 | **Parameters** 300 | - [`user`] *(`Object`)* Object returned by the `getUser` function. 301 | 302 | **Return *(`Boolean`)*** 303 | ``` 304 | Need to return a boolean that tell if the current user (returned by `getUser`) is logged. 305 | ``` 306 | 307 | **default** 308 | ```js 309 | isUserLogged = userData => !!userData && Object.keys(userData).length > 0; 310 | ``` 311 | *By default, `isUserLogged` returns true if `fetchUser` returns a non-empty object* 312 | 313 | ### 5.2 - `Authmanager` utils 314 | **react-authmanager** also provides some utilities to manage the manager from your app: 315 | ```js 316 | import Authmanager from 'react-authmanager'; 317 | 318 | // will return the current stored token, or null, see below 319 | const token = Authmanager.getToken() 320 | ``` 321 | 322 | #### `getToken()` 323 | Returns the current stored token (in *localStorage*). You should use `getToken` to authorize your requests to the server 324 | 325 | **Return *(`String`)*** 326 | ``` 327 | Returns the token stored after the `fetchToken` call 328 | ``` 329 | 330 | **example with axios** 331 | ```js 332 | axios.defaults.transformRequest.push((data, headers) => { 333 | const token = Authmanager.getToken(); 334 | if (token) headers.common['Authorization'] = 'Bearer ' + token; 335 | 336 | return data; 337 | }); 338 | ``` 339 | 340 | #### `setToken([token])` 341 | Manually set a token. You can call the `setToken` if you want to implements your own login function. 342 | 343 | **Parameters** 344 | - [`token`] *(`String`)* String token that will be returned by the `fetchToken` function. 345 | 346 | **Return *utils (`Object`)*** 347 | ``` 348 | Need to return a boolean that tell if the current user (returned by `getUser`) is logged. 349 | ``` 350 | 351 | **example** 352 | ```js 353 | Authmanager.setToken('aValidToken'); 354 | Authmanager.getUser(); 355 | ``` 356 | 357 | #### `addGuard([guard])` 358 | Create a guard at the manager level, you will be able to reuse the guard just by giving its name 359 | 360 | **Parameters** 361 | - [`guard`] *(`Function`)* A function that returns a component or call the next function to render the default component. 362 | 363 | **Return *Component | next()*** 364 | ``` 365 | Need to return a valid React component or call the next function given in parameters. 366 | ``` 367 | 368 | **example** 369 | ```js 370 | Authmanager.addGuard('loggedGuard', (user, next) => { 371 | if (user.loading) 372 | return
loading
; 373 | 374 | if (user.logged) 375 | return next(); 376 | 377 | return
login
; 378 | }); 379 | ``` 380 | 381 | #### `getUser()` 382 | Call the `fetchUser` function and update the redux store. You can use this function to refresh the current logged user from the server 383 | 384 | **Return *utils (`Object`)*** 385 | ``` 386 | Returns a promise that resolves the new user data 387 | ``` 388 | 389 | --- 390 | 391 | 🚀 392 | --------------------------------------------------------------------------------