eazy-auth
Easy auth stuff \w redux
Battery included but extractable package to automate auth boring stuff.
The stack is redux
, react
for UI, redux-saga
for side effects and react-router-dom
for routing.
Install
yarn add eazy-auth
or
npm install eazy-auth --save
Cheat sheet
// Redux// Make the auth reducer using auth as reducer keyconst rootReducer = // Redux saga// Make the auth flow (managed using redux-saga)// you get authFlow a saga to fork to bootstrap auth// authCall a version of redux-saga call function but with auth token curriedconst authFlow authCall = { // Bootstrap the auth // when user logged in for the first time eazy-auth save the tokens in local storage // when user return to app eazy-auth take tokens from local storage and perform a me call // (try to refresh tokens if function is provided) if all is ok user data are stored in redux // and update tokens in local storage if needed otherwise local storage is cleared // authCall is a enhance version of redux-saga call https://redux-saga.js.org/docs/api/#callfn-args // but it call the function with the access token curried so you can do authenticated api call // plus if the api reject and the exception contains a status key with 401 eazy-auht try to refresh token and // retrying the call if fail again or no refresh function is provided logout and clear state and local storage try const data = catch error // \\\TIP/// // for call api i personally use superagent https://github.com/visionmedia/superagent // for automate the injection of token you can use a helper like that or do a similar stuff \w other fetching libraries const withToken = token ? baseRequest : baseRequest const fetchUser = } // React// What you get? // Action creators // Selectors // ... And if you want o covenient high order component for login let <form onSubmit=handleSubmit> <div> <input type='email' ...email /> </div> <div> <input type='password' ...password /> </div> <div> <input type='submit' /> </div> loading && <div>Login...</div> error && <div>Bad credentials</div> </form> login = Login // React router v4 const App = <Provider store=store> <Router> <Switch> /* Redirect user to another route if not authenticated */ <AuthRoute path='/profile' exact component=Old /* Path to redirect */ redirectTo='/login' /* Spinner to use while loading */ spinner=null /* Remeber referrer when redirect guests? */ rememberReferrer=true /* Additional function to check permission on user and redirect */ redirectTest= userage > 27 ? false : '/' /> /* Redirect user to another route if authenticated */ <GuestRoute path='/login' exact component=Login spinner=null redirectTo='/' /* Redirect to referrer if user logged in? */ redirectToReferrer=true /> /* Simply if user has a token in local storage and not yet me has been performed wait until me complete before mounting component optionally show a spinner if you want */ <MaybeAuthRoute path='/home' exact component=Home spinner=null /> </Switch> </Router> </Provider>
authMiddleware
eazy-auth
was originally built with redux-saga
in mind but in certain situation you need to hook the auth "side effects" outside the redux-saga
environment for example directly in react components.
This is why the authMiddleware
was created.
Create auth middleware:
const authFlow authCall makeAuthMiddleware = const authMiddleware = const sagaMiddleware = const composeEnhancers = window__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || composeconst store = // IMPORTATION run authMiddleware before the sagaMiddleware const callAuthApiObservable callAuthApiPromise = authMiddlewaresagaMiddleware
callAuthApiPromise(apiCall, ...args)
apiCall: (accessToken)(...args) => Promise
Curry the accessToken
if any, logout on rejection matches { status: 401|403 }
and try refresh if a refresh call is given, if refresh is good re-try the apiCall
otherwis rejects.
Return a Promise.
callAuthApiObservable(apiCall, ...args)
apiCall: (accessToken)(...args) => Promise|Observable
Same as above but implement with observables.
Return a Observable.