UNPKG

31.2 kBMarkdownView Raw
1[![redux auth](https://github.com/lynndylanhurley/redux-auth/raw/master/docs/images/redux-auth-logo.gif)](https://github.com/lynndylanhurley/redux-auth)
2
3### Simple, secure authentication for react + redux
4
5[![npm version](https://badge.fury.io/js/redux-auth.svg)](https://badge.fury.io/js/redux-auth)
6[![Build Status](https://travis-ci.org/lynndylanhurley/redux-auth.svg)](https://travis-ci.org/lynndylanhurley/redux-auth)
7[![Coverage Status](https://coveralls.io/repos/lynndylanhurley/redux-auth/badge.svg?branch=master&service=github)](https://coveralls.io/github/lynndylanhurley/redux-auth?branch=master)
8
9
10# TL;DR - View the [Live Demo](http://redux-auth.herokuapp.com/)
11
12You can see a complete working example [here](http://redux-auth.herokuapp.com/). The code for the demo is [here](https://github.com/lynndylanhurley/redux-auth-demo).
13
14Click this button to deploy the demo app to your own server:
15
16[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/lynndylanhurley/redux-auth-demo)
17
18--
19
20# Features:
21
22* Supports isomorphic / universal / server-side rendering
23* [OAuth2 authentication components](#oauthsigninbutton)
24* Email authentication components, including:
25 * [User registration](#emailsignupform)
26 * [Password resets](#requestpasswordresetform)
27 * [Email sign in](#emailsigninform)
28* Seamless integration with the [devise token auth][dta] Rails gem.
29* Includes the following themes:
30 * [Material UI][material-ui]
31 * [React Bootstrap][react-bootstrap]
32 * A skank theme that you can style from scratch
33* Support for [multiple user types](#multiple-user-types)
34* **coming soon** React Native support
35* **coming soon** I18n support
36* **coming soon** Can be configured to work with any API
37
38This project comes bundled with a test app. You can run the demo locally by following these instructions, or you can use it [here][redux-auth-demo] in production.
39
40The demo uses [React][react], and the source can be found [here](https://github.com/lynndylanhurley/redux-auth/tree/master/dummy).
41
42--
43
44# Table of Contents
45
46* [About this plugin](#about-this-plugin)
47* [Installation](#installation)
48* [Components](#components)
49 * [EmailSignUpForm](#emailsignupform)
50 * [EmailSignInForm](#emailsigninform)
51 * [OAuthSignInButton](#oauthsigninbutton)
52 * [SignOutButton](#signoutbutton)
53 * [DestroyAccountButton](#destroyaccountbutton)
54 * [RequestPasswordResetForm](#requestpasswordresetform)
55 * [UpdatePasswordForm](#updatepasswordform)
56 * [AuthGlobals](#authglobals)
57* [Methods](#methods)
58 * [configure](#configure)
59 * [fetch](#fetch)
60* [Configuration](#configuration)
61* [Using Multiple User Types](#multiple-user-types)
62* [API Expectations](#extended-documentation)
63* [Contributing](#contributing)
64* [Development](#development)
65* [Callouts](#credits)
66
67# About this plugin
68
69This plugin relies on [token based authentication][token-auth-wiki]. This requires coordination between the client and the server. [Diagrams](#extended-documentation) are included to illustrate this relationship.
70
71This plugin was designed to work out of the box with the wonderful [devise token auth][dta] gem, but it's flexible enough to be used in just about any environment.
72
73**About security**: [read here][so-post] for more information on securing your token auth system. The [devise token auth][dta] gem has adequate security measures in place, and this plugin was built to work seamlessly with that gem.
74
75--
76
77# Installation
78
79Only npm is currently supported.
80
81~~~sh
82npm install redux-auth --save
83~~~
84
85If you want to use the [Material UI][material-ui] or [Bootstrap][react-bootstrap] themes, you will need to install those libraries as well.
86
87~~~sh
88# install material ui
89npm install material-ui --save
90
91# or bootstrap
92npm install react-bootstrap --save
93~~~
94
95Material UI uses inline styles so no further configuration is needed. But with the bootstrap theme, the CSS will also need to be included. Read more at the [React Bootstrap][react-bootstrap] project page.
96
97--
98
99# Usage
100
101## Components
102
103There are 3 Themes included in this module.
104
1051. [Material UI][material-ui]
1062. [Bootstrap][react-bootstrap]
1073. A default theme
108
109The default theme has no styling, and honestly it just looks really bad. But if you hate heavy UI frameworks and you like to style everything yourself, then you will love the default theme.
110
111All components can make their own API requests, display errors, and display success messages out of the box.
112
113The examples shown below use the Material UI theme.
114
115--
116
117### EmailSignUpForm
118
119A form used for email based registration.
120
121![Material UI email sign up][mui-email-sign-up]
122
123##### EmailSignUpForm props:
124
125* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block.
126* **`inputProps`**: An object containing the following attributes:
127 * **`email`**: An object that will override the email input component's default props.
128 * **`password`**: An object that will override the password input component's default props.
129 * **`passwordConfirmation`**: An object that will override the password confirmation input component's default props.
130 * **`submit`**: An object that will override the submit button component's default props.
131
132##### EmailSignUpForm usage
133
134~~~js
135// default theme
136import { EmailSignUpForm } from "redux-auth";
137
138// material ui theme
139import { EmailSignUpForm } from "redux-auth/material-ui-theme";
140
141// bootstrap theme
142import { EmailSignUpForm } from "redux-auth/bootstrap-theme";
143
144// render
145render: () {
146 return <EmailSignUpForm />;
147}
148~~~
149
150[View EmailSignUpForm API Expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/email-sign-up.md)
151
152--
153
154### EmailSignInForm
155
156A form used to sign in using accounts that were registered by email.
157
158![Material UI email sign in][mui-email-sign-in]
159
160##### EmailSignInForm props:
161
162* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block.
163* **`inputProps`**: An object containing the following attributes:
164 * **`email`**: An object that will override the email input component's default props.
165 * **`password`**: An object that will override the password input component's default props.
166 * **`submit`**: An object that will override the submit button component's default props.
167
168~~~js
169// default theme
170import { EmailSignInForm } from "redux-auth";
171
172// material ui theme
173import { EmailSignInForm } from "redux-auth/material-ui-theme";
174
175// bootstrap theme
176import { EmailSignInForm } from "redux-auth/bootstrap-theme";
177
178// render
179render: () {
180 return <EmailSignInForm />;
181}
182~~~
183
184[View EmailSignInForm API expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/email-sign-in.md)
185
186--
187
188### OAuthSignInButton
189
190A button used to authenticate using an OAuth provider (facebook, github, etc.).
191
192![Material UI OAuth sign in][mui-oauth-sign-in]
193
194##### OAuthSignInButton props:
195
196* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block.
197* **`provider`**: The name of the target provider service as represented in the `authProviderPaths` endpoint configuration.
198
199Any additional properties will be passed on the button component of the given theme.
200
201~~~js
202// default theme
203import { OAuthSignInButton } from "redux-auth";
204
205// material ui theme
206import { OAuthSignInButton } from "redux-auth/material-ui-theme";
207
208// bootstrap theme
209import { OAuthSignInButton } from "redux-auth/bootstrap-theme";
210
211// render
212render: () {
213 // using the default label
214 return <OAuthSignInButton />;
215
216 // or using custom label text
217 return <OAuthSignInButton>Custom Label</OAuthSignInButton>;
218}
219~~~
220
221[View OAuthSignInButton API expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/oauth-sign-in.md)
222
223--
224
225### SignOutButton
226
227A button used to end the current user's session.
228
229![Material UI sign out][mui-sign-out]
230
231##### SignOutButton props:
232
233* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block. If this property isn't provided, the current signed in user will be signed out regardless of their user type.
234
235Any additional properties will be passed on the button component of the given theme.
236
237~~~js
238// default theme
239import { SignOutButton } from "redux-auth";
240
241// material ui theme
242import { SignOutButton } from "redux-auth/material-ui-theme";
243
244// bootstrap theme
245import { SignOutButton } from "redux-auth/bootstrap-theme";
246
247// render
248render: () {
249 // using the default label
250 return <SignOutButton />;
251
252 // or using custom label text
253 return <SignOutButton>Custom Label</SignOutButton>;
254}
255~~~
256
257[View SignOutButton API expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/sign-out.md)
258
259--
260
261### DestroyAccountButton
262
263A button used to destroy the account of the current user. This will also end the destroyed user's session.
264
265![Material UI destroy account][mui-destroy-account]
266
267##### DestroyAccountButton props:
268
269* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block. If this property isn't provided, the current signed in user's account will be destroyed regardless of their user type.
270
271Any additional properties will be passed on the button component of the given theme.
272
273~~~js
274// default theme
275import { DestroyAccountButton } from "redux-auth";
276
277// material ui theme
278import { DestroyAccountButton } from "redux-auth/material-ui-theme";
279
280// bootstrap theme
281import { DestroyAccountButton } from "redux-auth/bootstrap-theme";
282
283// render
284render: () {
285 // using the default label
286 return <DestroyAccountButton />;
287
288 // or using custom label text
289 return <DestroyAccountButton>Custom Label</DestroyAccountButton>;
290}
291~~~
292
293[View DestroyAccountButton API Expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/destroy-account.md)
294
295--
296
297### RequestPasswordResetForm
298
299A form used to send password reset emails to users that forgot their password. When users click the link included in the email, they will be redirected to the site that the request was made from. A modal will appear that contains a form allowing the user to create a new password.
300
301![Material UI request password reset][mui-password-reset]
302
303##### RequestPasswordResetForm props:
304
305* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block.
306* **`inputProps`**: An object containing the following attributes:
307 * **`email`**: An object that will override the email input component's default props.
308 * **`submit`**: An object that will override the submit button component's default props.
309
310~~~js
311// default theme
312import { RequestPasswordResetForm } from "redux-auth";
313
314// material ui theme
315import { RequestPasswordResetForm } from "redux-auth/material-ui-theme";
316
317// bootstrap theme
318import { RequestPasswordResetForm } from "redux-auth/bootstrap-theme";
319
320// render
321render: () {
322 return <RequestPassswordResetForm />;
323}
324~~~
325
326[View RequestPasswordResetForm API Expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/request-password-reset.md)
327
328--
329
330### UpdatePasswordForm
331
332A form that can be used to change the current user's password.
333
334![Material UI update password][mui-update-password]
335
336##### UpdatePasswordForm props:
337
338* **`endpoint`**: The key of the target provider service as represented in the endpoint configuration block. If this value is not provided, the current user's password will be updated regardless of their user type.
339* **`inputProps`**: An object containing the following attributes:
340 * **`password`**: An object that will override the password input component's default props.
341 * **`passwordConfirmation`**: An object that will override the password confirmation input component's default props.
342 * **`submit`**: An object that will override the submit button component's default props.
343
344~~~js
345// default theme
346import { UpdatePasswordForm } from "redux-auth";
347
348// material ui theme
349import { UpdatePasswordForm } from "redux-auth/material-ui-theme";
350
351// bootstrap theme
352import { UpdatePasswordForm } from "redux-auth/bootstrap-theme";
353
354// render
355render: () {
356 return <UpdatePasswordForm />;
357}
358~~~
359
360[View UpdatePasswordForm API Expectations](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/update-password.md)
361
362--
363
364### AuthGlobals
365
366This component contains all of the modals used in authentication, and also the component that is used to pass credentials from the server to the client when using server side rendering.
367
368This component **MUST** live at the top level of your application **outside of your routes**.
369
370##### AuthGlobals example using redux-router
371
372The following example shows the relevant router configuration. Note that this is not a complete example. See the [demo app][redux-auth-demo] for a complete, working setup.
373
374~~~js
375// default theme
376import { AuthGlobals } from "redux-auth";
377
378// material ui theme
379import { AuthGlobals } from "redux-auth/material-ui-theme";
380
381// bootstrap theme
382import { AuthGlobals } from "redux-auth/bootstrap-theme";
383
384// your main app component. notice that AuthGlobals lives at the same level
385// as the app's children.
386class App extends React.Component {
387 render() {
388 return (
389 <div>
390 <AuthGlobals />
391 {this.props.children}
392 </div>
393 );
394 }
395}
396
397// example routes. the nested routes here will replace "this.props.children"
398// in the example above
399var routes = (
400 <Route path="/" component={App}>
401 <IndexRoute component={Main} />
402 <Route path="alt" component={Alt} />
403 <Route path="login" component={SignIn} />
404 <Route path="account" component={Account} onEnter={requireAuth} />
405 </Route>
406);
407~~~
408
409--
410
411## Methods
412
413### configure
414
415This must be run before your app is initialized. This should be run on both the server, and on the client. The server will need an additional argument containing information about the current request's cookies and location.
416
417##### configure arguments
418* **`endpoints`**: An object containing information about your API. This at least needs to contain the full path to your URL as the `apiUrl` property. See [here](#endpoint-config-options) for a complete list of endpoint config options.
419* **`settings`**: When rendering serverside, this will need to be an object that contains the following attributes:
420 * **`isServer`**: A boolean that must be set to `true` when rendering server-side.
421 * **`cookies`**: A string representation of the cookies from the current request. This will be parsed for any auth credentials.
422 * **`location`**: A string representation of the current request's URL.
423
424--
425
426##### configure example
427
428~~~js
429import { configure } from "redux-auth";
430
431// server-side usage
432store.dispatch(configure(
433 {apiUrl: "https://api.graveflex.com"},
434 {isServer: true, cookies, currentLocation}
435).then(({redirectPath, blank} = {}) => {
436 // if `blank` is true, this is an OAuth redirect and should not
437 // be rendered
438
439 // use your server to render your app, or redirect
440 // to another location if the user is unauthorized.
441
442 // see the demo app for a more complete example.
443});
444
445// client-side usage
446store.dispatch(configure(
447 {apiUrl: "https://api.graveflex.com"}
448).then(() => {
449 // your store should now have the current user. now render your
450 // app to the DOM. see the demo app for a more complete example.
451});
452~~~
453
454--
455
456### fetch
457A wrapper around the [whatwg fetch][whatwg-fetch] implementation that automatically sends and tracks authentication headers. See [here][fetch-spec] for the complete spec.
458
459Any requests to the API that rely on authentication will need to use the `fetch` function included in this library.
460
461--
462###### fetch example
463
464~~~js
465import { fetch } from "redux-auth";
466
467// usage
468fetch("http://api.mysite.com").then(resp => {
469 alert(`Api response: `${resp}`);
470});
471~~~
472
473--
474
475# Configuration
476
477This is the most difficult step, but only because configuring a [redux][redux] app is inherently difficult.
478
479The following example assumes that you are familiar with redux, and that you know how to [create a store][redux-create-store]. Also keep in mind that this is a really basic example that does not even include routing. See the [demo app][redux-auth-demo] for a more complete example.
480
481This example assumes a directory structure that looks like this:
482
483~~~
484src/
485 app.js
486 client.js
487 server.js
488~~~
489
490##### config shared by both client and server
491~~~js
492// app.js
493import React from "react";
494import {Provider} from "react-redux";
495import {configure, authStateReducer, AuthGlobals} from "redux-auth";
496import {createStore, compose, applyMiddleware, combineReducers} from "redux";
497import {AuthGlobals} from "redux-auth"
498
499class App extends React.Component {
500 render() {
501 return (
502 <div>
503 <AuthGlobals />
504 {this.props.children}
505 </div>
506 );
507 }
508}
509
510// create your main reducer
511const reducer = combineReducers({
512 auth: authStateReducer,
513 // ... add your own reducers here
514});
515
516// create your app's store.
517// note that thunk is required to use redux-auth
518const store = compose(
519 applyMiddleware(thunk),
520 // ... add additional middleware here (router, etc.)
521)(createStore)(reducer);
522
523// a single function can be used for both client and server-side rendering.
524// when run from the server, this function will need to know the cookies and
525// url of the current request. also be sure to set `isServer` to true.
526export function renderApp({cookies, isServer, currentLocation} = {}) {
527 // configure redux-auth BEFORE rendering the page
528 store.dispatch(configure(
529 // use the FULL PATH to your API
530 {apiUrl: "http://api.catfancy.com"},
531 {isServer, cookies, currentLocation}
532 ).then({redirectPath, blank} = {}) => {
533 if (blank) {
534 // if `blank` is true, this is an OAuth redirect and should not
535 // be rendered
536 return <noscript />;
537 } else {
538 return (
539 <Provider store={store} key="provider">
540 <App />
541 </Provider>
542 );
543 }
544 });
545}
546~~~
547
548##### server-side rendering configuration
549~~~js
550// server.js
551import qs from "query-string";
552import {renderToString} from "react-dom/server";
553import { renderApp } from "./app";
554
555// render the main app component into an html page
556function getMarkup(appComponent) {
557 var markup = renderToString(appComponent)
558
559 return `<!doctype html>
560 <html>
561 <head>
562 <title>Redux Auth – Isomorphic Example</title>
563 </head>
564 <body>
565 <div id="react-root">${markup}</div>
566 <script src="/path/to/my/scripts.js"></script>
567 </body>
568 </html>`;
569}
570
571// this function will differ depending on the serverside framework that
572// you decide to use (express, hapi, etc.). The following example uses hapi
573server.ext("onPreResponse", (request, reply) => {
574 var query = qs.stringify(request.query);
575 var currentLocation = request.path + (query.length ? "?" + query : "");
576 var cookies = request.headers.cookies;
577
578 renderApp({
579 isServer: true,
580 cookies,
581 currentLocation
582 }).then(appComponent => {
583 reply(getMarkup(appComponent));
584 });
585}
586~~~
587
588##### client side rendering configuration
589
590~~~js
591// client.js
592import React from "react";
593import ReactDOM from "react-dom";
594import { renderApp } from "./app";
595
596const reactRoot = window.document.getElementById("react-root");
597renderApp().then(appComponent => {
598 ReactDOM.render(appComponent, reactRoot);
599});
600~~~
601
602**Note:** be sure to include the [`AuthGlobals`](#authglobals) component at the top level of your application. This means **outside** of your `Routes` if you're using something like [react-router][react-router].
603
604See below for the complete list of configuration options.
605
606# Multiple user types
607
608This plugin allows for the use of multiple user authentication endpoint configurations. The following example assumes that the API supports two user classes, `User` and `EvilUser`. The following examples assume that `User` authentication routes are mounted at `/auth,` and the `EvilUser` authentication routes are mounted at `evil_user_auth`.
609
610### Multiple user type configuration
611
612When using a single user type, you will pass a single object to the `configure` method as shown in the following example.
613
614~~~js
615store.dispatch(configure({
616 apiUrl: 'https://devise-token-auth.dev'
617}));
618~~~
619
620When using multiple user types, you will instead pass an array of configurations, as shown in the following example.
621
622~~~javascript
623store.dispatch(configure([
624 {
625 default: {
626 apiUrl: 'https://devise-token-auth.dev'
627 }
628 }, {
629 evilUser: {
630 apiUrl: 'https://devise-token-auth.dev',
631 signOutUrl: '/evil_user_auth/sign_out',
632 emailSignInPath: '/evil_user_auth/sign_in',
633 emailRegistrationPath: '/evil_user_auth',
634 accountUpdatePath: '/evil_user_auth',
635 accountDeletePath: '/evil_user_auth',
636 passwordResetPath: '/evil_user_auth/password',
637 passwordUpdatePath: '/evil_user_auth/password',
638 tokenValidationPath: '/evil_user_auth/validate_token',
639 authProviderPaths: {
640 github: '/evil_user_auth/github',
641 facebook: '/evil_user_auth/facebook',
642 google: '/evil_user_auth/google_oauth2'
643 }
644 }
645 }
646], {
647 isServer,
648 cookies,
649 currentLocation
650));
651~~~
652
653### Using multiple endpoints with redux-auth components
654
655All components accept an `endpoint` attribute that will determine which of the endpoint configurations the component should use. For forms that are used by non-authenticated users users (`EmailSignInForm`, `OAuthSignInButton`, etc.), the first configuration in the endpoint config will be used as the default if this value is not provided. For forms used by authenticated users (`SignOutButton`, `UpdatePassword`, etc.), the current user's endpoint will be used by default if this value is not provided.
656
657The following example assumes a configuration where two endpoints have been defined, `default` and `auth`:
658
659##### Component example:
660~~~js
661import { EmailSignInForm } from "redux-auth";
662
663// within render method
664<EmailSignInForm endpoint="alt" />
665~~~
666
667--
668
669### Endpoint config options
670
671This is the complete list of options that can be passed to the endpoint config.
672
673~~~js
674import { config } from "redux-auth";
675
676// ... configure store, routes, etc... //
677
678store.dispatch(configure({
679 apiUrl: 'https://devise-token-auth.dev',
680 signOutPath: '/evil_user_auth/sign_out',
681 emailSignInPath: '/evil_user_auth/sign_in',
682 emailRegistrationPath: '/evil_user_auth',
683 accountUpdatePath: '/evil_user_auth',
684 accountDeletePath: '/evil_user_auth',
685 passwordResetPath: '/evil_user_auth/password',
686 passwordUpdatePath: '/evil_user_auth/password',
687 tokenValidationPath: '/evil_user_auth/validate_token',
688 authProviderPaths: {
689 github: '/evil_user_auth/github',
690 facebook: '/evil_user_auth/facebook',
691 google: '/evil_user_auth/google_oauth2'
692 }
693}).then(// ... render your app ... //
694~~~
695
696#### apiUrl
697###### string
698The base route to your api. Each of the following paths will be relative to this URL. Authentication headers will only be added to requests with this value as the base URL.
699
700--
701
702#### tokenValidationPath
703###### string
704Path (relative to `apiUrl`) to validate authentication tokens. [Read more](#token-validation-flow).
705
706--
707
708#### signOutPath
709###### string
710Path (relative to `apiUrl`) to de-authenticate the current user. This will destroy the user's token both server-side and client-side.
711
712--
713
714#### authProviderPaths
715###### object
716An object containing paths to auth endpoints. Keys should be the names of the providers, and the values should be the auth paths relative to the `apiUrl`. [Read more](#oauth-2-authentication-flow).
717
718--
719
720#### emailRegistrationPath
721###### string
722Path (relative to `apiUrl`) for submitting new email registrations. [Read more](#email-registration-flow).
723
724--
725
726#### accountUpdatePath
727###### string
728Path (relative to `apiUrl`) for submitting account update requests.
729
730--
731
732#### accountDeletePath
733###### string
734Path (relative to `apiUrl`) for submitting account deletion requests.
735
736--
737
738#### emailSignInPath
739###### string
740Path (relative to `apiUrl`) for signing in to an existing email account.
741
742--
743
744#### passwordResetPath
745###### string
746Path (relative to `apiUrl`) for requesting password reset emails.
747
748--
749
750#### passwordUpdatePath
751###### string
752Path (relative to `apiUrl`) for submitting new passwords for authenticated users.
753
754--
755
756# Extended Documentation
757
758Follow these links to learn more about what the API expects from this library, and to see diagrams on how it all fits together. All of this stuff happens automatically when using this library with the [devise token auth gem][dta], but this information will be useful if you need to implement your own API.
759
760* [Signing In With Email](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/email-sign-in.md)
761* [Signing In With OAuth](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/oauth-sign-in.md)
762* [Validating Returning Users](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/token-validation.md)
763* [Managing Session Tokens](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/token-management.md)
764* [Signing Out](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/sign-out.md)
765* [Registering With Email](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/email-sign-up.md)
766* [Requesting Password Resets](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/request-password-reset.md)
767* [Destroying Accounts](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/destroy-account.md)
768* [Updating Passwords](https://github.com/lynndylanhurley/redux-auth/blob/master/docs/api-expectations/update-password.md)
769
770# Contributing
771
7721. Create a feature branch with your changes.
7731. Write some test cases.
7741. Make all the tests pass.
7751. Issue a pull request.
776
777I will grant you commit access if you send quality pull requests.
778
779# Development
780
781### Running the dev server
782
783There is a test project in the `demo` directory of this app. To start a dev server, perform the following steps.
784
7851. `cd` to the root of this project.
7861. `cd dummy`
7871. `npm install`
7881. `npm run watch`
789
790A hot-reloading dev server will start on [localhost:8000](http://localhost:8000). The test suite will be run as well.
791
792### Running the tests
793
794If you just want to run the tests, follow these steps:
795
7961. `cd` into the root of this project
7971. `npm install`
7981. `npm test`
799
800### Testing against a live API
801
802This plugin was built against [this API](https://github.com/lynndylanhurley/devise_token_auth_demo). You can use this, or feel free to use your own.
803
804# Credits
805
806Thanks to the following contributors:
807
808* [@transedward](https://github.com/transedward) for letting me use the name `redux-auth`.
809
810Code and ideas were stolen from the following sources:
811
812* [this SO post on token-auth security][so-post]
813* [this SO post on string templating](http://stackoverflow.com/questions/14879866/javascript-templating-function-replace-string-and-dont-take-care-of-whitespace)
814* [this brilliant AngularJS module][ng-token-auth]
815
816# License
817
818WTFPL © Lynn Dylan Hurley
819
820[ng-token-auth]: https://github.com/lynndylanhurley/ng-token-auth
821[dta]: https://github.com/lynndylanhurley/devise_token_auth
822[token-auth-wiki]: http://stackoverflow.com/questions/1592534/what-is-token-based-authentication
823[so-post]: http://stackoverflow.com/questions/18605294/is-devises-token-authenticatable-secure
824[jquery]: https://jquery.com/
825[jquery-cookie]: https://github.com/carhartl/jquery-cookie
826[jquery-deparam]: https://www.npmjs.com/package/jquery-deparam
827[pubsub-js]: https://github.com/mroderick/PubSubJS
828[bower]: http://bower.io/
829[npm]: https://www.npmjs.com/
830[browserify]: http://browserify.org/
831[cors]: http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
832[common-js]: http://en.wikipedia.org/wiki/CommonJS
833[dfd]: https://api.jquery.com/jQuery.Deferred/
834[angular]: https://angularjs.org/
835[react]: http://facebook.github.io/react/
836[react-bootstrap]: https://react-bootstrap.github.io/
837[material-ui]: http://www.material-ui.com
838[redux]: http://rackt.org/redux/index.html
839[redux-create-store]: http://rackt.org/redux/docs/basics/Store.html
840[react-router]: https://github.com/rackt/react-router
841[redux-auth-demo]: http://github.com/lynndylanhurley/redux-auth-demo
842[whatwg-fetch]: https://github.com/github/fetch
843[fetch-spec]: https://fetch.spec.whatwg.org/
844
845[o-auth-flow]: https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/omniauth-flow.jpg
846[token-validation-flow]: https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/validation-flow.jpg
847[email-registration-flow]: https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/email-registration-flow.jpg
848[email-sign-in-flow]: https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/email-sign-in-flow.jpg
849[password-reset-flow]: https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/password-reset-flow.jpg
850
851[mui-destroy-account]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/destroy-account.gif
852[mui-email-sign-in]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/email-sign-in.gif
853[mui-email-sign-up]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/email-sign-up.gif
854[mui-oauth-sign-in]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/oauth-sign-in.gif
855[mui-password-reset]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/request-password-reset.gif
856[mui-update-password]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/update-password.gif
857[mui-sign-out]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/gifs/sign-out.gif
858
859[mui-error-dialog]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/images/mui-error-dialog.png
860[mui-inline-errors]: https://github.com/lynndylanhurley/redux-auth/raw/master/docs/images/mui-inline-errors.png