@gggdomi/rrh-auth v0.3.5
Plugin for RRH to help with authentication workflow. Store credentials, authenticate requests and redirect to login if needed.
Installation
Pre-requisites
- RRH need to be set up
- connected-react-router is required to be able to change location by dispacthing action. It's a drop-in replacement for
react-router
and might be of use if you mix react-router with redux in your project.
yarn add @gggdomi/rrh-auth
Add to RRH plugins
// index.js
import rrh from '@gggdomi/rrh'
import rrhAuth from '@gggdomi/rrh-auth'
rrh.plugins = [rrhAuth]
Add auth reducer
// reducers.js
import { rrhReducers } from '@gggdomi/rrh' // from RRH readme
import { authReducer } from '@gggdomi/rrh-auth'
export const rootReducer = combineReducers({
your: yourReducer,
rrh: combineReducers(rrhReducers), // from RRH readme
auth: authReducer,
})
Add rrh-auth sagas to the app
// index.js
import rrhAuthSagas from '@gggdomi/rrh-auth/src/sagas'
// configure saga middleware...
rrhAuthSagas.map(sagaMiddleware.run)
Tell which server-side endpoints are used to login
isLoginEndpoint
will tell rrh-auth
to look for credentials when calling these endpoints
import rrh from '@gggdomi/rrh'
export const postLogin = rrh.new('SUBMIT_LOGIN', '/login/', {
method: 'POST',
isLoginEndpoint: true, // here
})
Usage
Dispatch actions to log in/out
import { logOutAction } from '@gggdomi/rrh-auth'
import { postLogin } from './actions'
const ExComponent = ({ triggerLogOut }) => (
<button onClick={triggerLogIn}>Log in</button>
<button onClick={triggerLogOut}>Log out</button>
)
const mapDispatchToProps = dispatch => ({
triggerLogIn: () => dispatch(postLogin.Start({
// using postLogin route created above
data: {user: "John", pass: "123456" }
})),
triggerLogOut: () => dispatch(logOutAction()),
})
export default connect(null, mapDispatchToProps)(ExComponent)
Configuration
Right now rrh-auth
only supports authentication via JWT tokens and Authorization header. Other authentication means could easily be added, feel free to open an issue if needed.
// rrhAuth.config:
{
jwt: {
// to use rrh-auth with jwt (default: true)
use: true,
// how to extract JWT token from the server response
getToken: data => data.access_token, // <- default value
// how to create the Authorization header given the token
makeAuthHeader: accessToken => 'Bearer ' + accessToken, // <- default value
// how to extract user infos from decoded token
getInfos: data => data.identity, // <- default value
},
// set to true to automatically logout when getting a 401 status (ie. invalid/missing credentials) (default: true)
shouldLogoutOn401: true,
// if not null, we push this URL (default: '/')
redirectToOnLoggedIn: '/home/',
// if not null, set to true to automatically display login page when logging out (default: '/login/')
loginRoute: '/login/',
// if not null, this endpoint will be called on the server when logging out (default: '/logout/')
logoutEndpoint: '/logout/',
}
Example:
Let's say your API:
- on successful login (POST on '/login/'), the server returns a response containing a token
{ apiToken: "xxxxxxxxxxxx" }
- is authenticated via Authorization header, with format "Token xxxxxxxxxxxxx".
- once decoded, the user infos are available on the
infos
property of the token - you need to GET /destroy/ to logout serverside
To configure rrh-auth accordingly:
import rrhAuth from '@gggdomi/rrh-auth'
rrhAuth.config.jwt.getToken = data => data.apiToken
rrhAuth.config.jwt.makeAuthHeader = token => `Token ${token}`
rrhAuth.config.jwt.getInfos = x => x.infos
rrhAuth.config.logoutEndpoint = '/destroy/'
Routes options
import rrh from '@gggdomi/rrh'
export const fetchPosts = rrh.new('FETCH_POSTS', '/posts/', {
// will tell rrh-auth to look for credentials when calling these endpoints (default: false)
isLoginEndpoint: false,
// if set to true, we won't redirect to login for this route if we get a 401 from server (default: false)
ignore401: true,
// if set to false, we won't attach token to request (default: true)
authenticated: false,
})
Advanced customization
Redirection to login page on logout or invalid credentials, and calling a server endpoint on logout are built in rrh-auth
by default. If you need more specific behavior, you can set loginRoute
and logoutEndpoint
to null
and then take logOutAction
and loggedInAction
in your own sagas
Example:
import { logOutAction, loggedInAction } from '@gggdomi/rrh-auth'
import { push } from 'connected-react-router'
export function* loggedInSaga() {
yield takeEvery(loggedInAction().type, function*(action) {
// We do some stuff and redirect to root on successful login
doSomeStuff()
yield put(push('/'))
})
}
export function* logOutSaga() {
yield takeEvery(logOutAction().type, function*(action) {
// we do some stuff on logout
doSomeStuff()
})
}
// don't forget to then run the sagas