ackee-redux-token-auth
The library aims to handle authentication logic with token based flow.
Main features
- automatically refresh access token before it becomes expired
- persisting tokens state in local or session storage (optional)
- automatically fetching an authorized user after successful tokens retrieval from a storage
- simple API for auth state management:
getAuthStateChannel
, withAuthSession
Requirements
The library works best with React apps that use Redux and Redux Saga (since the authentication logic is heavily integrated with both these libraries).
Table of contents
Installing
Using npm:
$ npm install ackee-redux-token-auth
Using yarn:
$ yarn add ackee-redux-token-auth
Initialization
configure(config: Object, options: Object) => void
Sets the package configuration with an config object. Following config properties are supported:
config
:
authenticate: Function
- requiredrefreshTokens: Function
- requiredgetAuthUser: Function
- requiredshouldRefresh: Function
options
:
tokens
persistence: String
- See detailsrequestDurationEstimate: Number
minRequiredExpiration: Number
Any of the functions can also be a saga generator.
authenticate(credentials: any) => { user: any, tokens: any }
Required. This method is called when a login(credentials)
action is dispatched. These credentials are passed to authenticate
method.
The method is expected to return/or resolve with an Object with props user, tokens
or throw an error. User and tokens are then stored as is to the redux state for later use (state.auth.user
).
refreshTokens(tokens: Object) => tokens:Object
Required. This method is called when the timeout for refreshing tokens ends or when tokens are expired after retrieval from a local storage. This triggers the token-refresh process.
Function is expected to return/or resolve with an tokens Object: ({ [tokenName: string]: token }
)
getAuthUser(void) => user:any
Required. This method is called when tokens are successfully retrieved from a local storage.
Function is expected to return/or resolve with a user object.
[DEPRECATED]shouldRefresh(error: Error) => boolean
Optional. This function is called when the requestFn
catches an error and should decide, whether to refresh the tokens and retry the action or not.
Default: () => true
.
saga() => ReduxSaga
Initializes the saga handlers generator. This should be passed along with your other sagas.
reducer: ReduxReducer
The lib reducer. Needs to be plugged in under the auth
key. Reducer name is not-yet configurable.
Initialization overview
import * as ReduxAuth from 'ackee-redux-token-auth';
ReduxAuth.configure({
authenticate,
refreshTokens,
getAuthUser,
});
function*() {
yield all([ReduxAuth.saga()])
}
const rootReducer = combineReducers({
auth: ReduxAuth.reducer
});
API
Constants
tokens
Action creators
login(credentials: Object) => ReduxAction
The credentials
object is passed to authenticate(credentials)
method you've provided in the configure
method.
logout() => ReduxAction
Triggers a user logout. This clears the state of any auth data (tokens from local storage included).
Action types
Access token flow
ACCESS_TOKEN_AVAILABLE
Access token becomes available when one of following events successfully finished: login, local tokens retrieval or tokens refreshment.
It's guaranteed that ACCESS_TOKEN_UNAVAILABLE
action will be dispatched first, before another trigger of ACCESS_TOKEN_AVAILABLE
.
ACCESS_TOKEN_UNAVAILABLE
Access token becomes unavailable on logout or when tokens refreshment start. It's also guaranteed that ACCESS_TOKEN_AVAILABLE
action will be dispatched first, before another trigger of ACCESS_TOKEN_UNAVAILABLE
.
Authentication session flow
AUTH_SESSION_START
Once the application has available valid access token, this action is dispatched. It's guaranteed that AUTH_SESSION_END
must be triggered first before another trigger.
AUTH_SESSION_PAUSE
The action is triggered on start of access token refreshment.
AUTH_SESSION_RESUME
If access token refreshment was successful, AUTH_SESSION_RESUME
is triggered. It's guaranteed it will be dispatched only after AUTH_SESSION_PAUSE
action.
AUTH_SESSION_END
If access token refreshment fails or AUTH_LOGOUT
action§ is triggered, AUTH_SESSION_END
is triggered.
Selectors
authUser(state: Object) => user:any
Gets the user returned from authenticate
method.
isLoggedIn(state: Object) => Boolean
Returns true
whether user is logged in, false
otherwise.
isLoggingIn(state: Object) => Boolean
Returns true
whether the login process is taking place, false
otherwise.
isUserFetching(state: Object) => Boolean
Utilities
withAuthSession(fn: Function) => void
A generator function that receives any function as 1st parameter. The provided function will be launched on AUTH_SESSION_START
action and cancelled on AUTH_SESSION_END
.
Note that withAuthSession
is a blocking task (if you need to make it non-blocking one, use it with fork
effect).
Example
import { withAuthSession } from 'ackee-redux-token-auth';
function* myAuthSaga() {}
export default function*() {
yield withAuthSession(myAuthSaga);
}
getAuthStateChannel(void) => channel
A generator function that returns action channel with following available actions:
ACCESS_TOKEN_AVAILABLE
ACCESS_TOKEN_UNAVAILABLE
AUTH_SESSION_START
AUTH_SESSION_PAUSE
AUTH_SESSION_RESUME
AUTH_SESSION_END
Example
import { takeEvery } from 'redux-saga/effects';
import { getAuthStateChannel, actionTypes } from 'ackee-redux-token-auth';
function* logOutEveryAuthStateStep() {
const authStateChannel = yield getAuthStateChannel();
yield takeEvery(authStateChannel, function*(action) {
switch (action.type) {
case actionTypes.ACCESS_TOKEN_AVAILABLE: {
const accessToken = action.payload;
break;
}
case actionTypes.ACCESS_TOKEN_UNAVAILABLE:
break;
}
});
}
[DEPRECATED] authorizedFn(handler: Function)
A saga wrapper for the given handler
Function or a saga generator.
The handler is called with { ...tokens, user }
you returned in configure.authenticate
and configure.refreshTokens
.
HOC
authorizable(AuthorizableComponent, Firewall, Loader) => AuthorizedComponent
High order component that based on current state of the auth
reducer renders one of these components:
AuthorizableComponent
it is rendered only if an authorized user had been fetched (-> state.auth.user
)Firewall
is rendered if application isn't authorizedLoader
(optional) is renderer whenever the app can't determinate if it's authorized or not (e.g. when app is loading and it doesn't know yet if tokens are available or not)
Example
import React from 'react';
import { authorizable } from 'ackee-redux-token-auth/lib/HOC';
const AuthContent = <div>User is logged in</div>;
const Firewall = <div>Please login</div>;
const Loader = <div>Loading...</div>;
const AuthorizedComponent = authorizable(AuthContent, Firewall, Loader);
export default AuthorizedComponent;
Tokens management logic
More detail description of the Tokens management logic.
Migration guides from 1.x.x
to 2.0.x
The configure
method now accept an object with following changes:
refreshTokens
function is now requiredgetAuthUser
is a required function, that returns a user object.
The configure method should now look like this:
import { configure } from 'ackee-redux-token-auth';
configure({
autheticate,
refreshTokens,
getAuthUser,
});