Skip to content

Instantly share code, notes, and snippets.

@s-petersson
Last active March 7, 2018 00:43
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save s-petersson/093872bde19def5d7ce4 to your computer and use it in GitHub Desktop.
Save s-petersson/093872bde19def5d7ce4 to your computer and use it in GitHub Desktop.
Basic Redux Auth
export function configureFetch () {
const configuredFetch = (endpoint, options) => {
const initialOptions = {
headers: {
Authorization: Cookies.get('token')
}
}
const mergedOptions = _.merge(initialOptions, options);
return fetch(endpoint, mergedOptions);
}
if (__CLIENT__) {
self.__fetch = configuredFetch;
} else if (__SERVER__) {
global.__fetch = configuredFetch;
}
}
import { validateToken } from 'utils/api/auth';
import DashBoard from 'routes/dashboard';
import LoginRoute from 'routes/login';
export default {
childRoutes: [
DashBoard,
LoginRoute
],
onEnter: (nextState, replaceWith, callback) => {
validateToken()
.then(
response => {
const next = nextState.state && nextState.state.next;
if (nextState.location.pathname === '/login') {
replaceWith(null, next || '');
}
callback();
return response;
},
error => {
const next = nextState.state && nextState.state.next;
if (nextState.location.pathname !== '/login') {
replaceWith(null, '/login');
}
callback();
return error;
}
);
}
}
import { setToken, setUser } from 'ducks/login';
import routes from 'routes';
configureFetch();
const store = generateStore({}, routes);
store.dispatch(setUser(Cookies.get('user')));
React.render(
<App store={store} routes={mappedRoutes} />,
document.getElementById('root')
);
export default createReducer('login', initialState, {
[TRY]: (state, action) => (
state.mergeIn(['status'], { isTrying: true, errorReason: '' })
),
[SUCCESS]: (state, action) => {
return state.merge({ id: action.payload.user })
.mergeIn(['status'], { isTrying: false, errorReason: '' });
},
[ERROR]: (state, action) => (
state.mergeIn(['status'], { isTrying: true, errorReason: '', token: '' })
),
[LOGOUT]: (state, action) => state.mergeIn(['status'], {
isTrying: false,
errorReason: '',
id: null
}),
[SET_USER]: (state, action) => (
state.merge({ id: action.payload.result.user })
),
[CURRENT_REQUEST]: (state, action) => (
state.mergeIn(['status'], { isFetching: true })
),
[CURRENT_SUCCESS]: (state, action) => (
state.mergeIn(['status'], { isFetching: false })
),
[CURRENT_ERROR]: (state, action) => (
state.mergeIn(['status'], { isFetching: false })
)
});
export function setUser (userId) {
return {
type: SET_USER,
payload: { result: { user: userId } }
}
}
/*
* This method is called whenever the user presses the login button and
* he or she had the correct credentials. It will redirect the user to
* the next page (or home, if none was supplied.)
*/
function loginSuccess () {
return (response) => (
(dispatch, getState) => {
const routerLocation = getState().router.location
// If we're on the client we need to set a cookie so that
// the server renderer can fetch that cookie on a page refresh
// thus keeping the user logged in.
if (__CLIENT__) {
Cookies.set('token', response.token);
Cookies.set('user', response.user);
}
// Transition the user to next path or to /home.
// This is a side-effect in an action and shouldn't be done according
// to best-practice. But setting up a listener seems kind of overkill.
const next = routerLocation.state && routerLocation.state.next;
dispatch(pushState({}, next || '/'));
}
)
}
export function login (email, password) {
return {
types: [TRY, SUCCESS, ERROR],
payload: {
promise: API.authenticate(email, password),
onSuccessAction: loginSuccess()
}
}
}
export default {
path: '/',
component: DashBoard,
childRoutes: [
ProfilePage,
SomeListPage
]
}
export default {
path: '/login',
component: Login
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment