Skip to content

Instantly share code, notes, and snippets.

@Dr-Nikson
Last active October 23, 2017 17:16
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Dr-Nikson/f39c7dbeef384966c5ec to your computer and use it in GitHub Desktop.
Save Dr-Nikson/f39c7dbeef384966c5ec to your computer and use it in GitHub Desktop.
This is a redux-auth concept

This gist is about token-based authentication (who you are?) with redux

Currently it for clent-side apps only. Not for universall (isomorphic) apps. Will add it soon

0. Requirements

I'm using the promise middleware to dispatch actions like this:

dispatch({
  types: [ 'ACTION_START', 'ACTION_SUCCESS', 'ACTION_FAILURE' ],
  promise: new Promise(...),
});

If you want to use another implementation - just change action object

1. First of all you need to add auth reducer from reducer.js

2. Create a login form and dispatch check action (from auth-actions.js) on form submit

import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import MyLoginForm from './components/MyLoginForm';
import { check } from './auth-actions';

const mapDispatchToProps = (dispatch) => bindActionCreators({
  onSubmit: check
}, dispatch);
const MyLoginFromContainer = connect(null, mapDispatchToProps)(MyLoginForm);

ReactDOM.render(<MyLoginFromContainer />, document.getElementById('app'));

3. Token usage

After successful auth you'll get the token and the data inside your auth reducer state. So, if you want to add token to your future requests just use applyToken function from helpers.js Let's say your auth-header look like: Authorization: Bearer <token>

In this case we need to use thunk-middleware because in action creator we need to obtain the token from state

// someActions.js
import fetch from 'isomorphic-fetch';
import applyToken from './helpers';

const apiUrl = 'https://my-super-api.com/v1/do-job';

export function doJobAction(data) {
  return (dispatch, getState) => {
    const token = getSate().auth.token;
    const requestOptions = {
      body: JSON.stringify(data),
      method: 'POST',
      headers: { 
        'Content-type': 'application/json',
        'Accept': 'application/json'
      }
    };
    // applyToken before request
    const request = fetch(authUrl, applyToken(requestOptions, token));
    
    return dispatch({
      types: [ 'DO_JOB_START', 'DO_JOB_SUCCESS', 'DO_JOB_FAILURE' ],
      promise: request,
    });
  };
}
import fetch from 'isomorphic-fetch';
const authUrl = 'https://my-super-api.com/v1/auth';
export function check(login, password) {
// here we need to create url like
// https://my-super-api.com/v1/auth?login=luke&password=skywalker
// you can use any createQueryString func that transforms obj to query string
const request = fetch(authUrl + createQueryString({ login, password }), {
headers: { 'Accept': 'application/json' },
});
return {
types: [ 'AUTH_CHECK_START', 'AUTH_CHECK_SUCCESS', 'AUTH_CHECK_FAILURE' ],
promise: request,
}
}
export function applyHeaders(request, headers) {
return { ...request, headers: { ...request.headers, ...headers } };
}
export function applyToken(request, token) {
return applyHeaders(request, { 'Authorization': 'Bearer ' + token });
}
const initialSate = {
username: 'guest',
};
function auth(state = initialState, action = {}) {
switch (action.type) {
case AUTH_CHECK_SUCCESS:
// you can get any info from token here.
// It's just optional
// For example - if you're using JWT
// http://jwt.io/
const token = action.auth.token;
// token looks like base64(<header>).base64(<payload>).base64(<signature>)
// let's say our payload looks like:
// {
// name: "John Doe",
// group: "admin"
// }
const { name, group } = atob(token.split('.', 3)[1]);
return {
...state,
token,
username: name,
group,
}
default:
return state
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment