-
npm run dev
Based on coded authored auth server in the Udemy course Advanced React by Stephen Grieder on Udemy - I have documented tricky parts, adding notes, and implemented most of the code which he authored originally, although ocassionally made necessary modifications.
Server Setup - Authentication - Sections (27)
- Authentication diagram
- Cookies vs Tokens diagram
- Scalable Architecture diagram
- in server/ >npm init
-
npm install --save express mongoose morgan body-parser
- server/index.html and .gitignore
- node 5.5 does note have all ES6 so we'll use require for imports
- import express, http, bodyParser, morgan, app
- setup port, server, server.listen and log
- add morgan and bodyParser middleware to app setup
-
npm install --save nodemon (watch directory for changes and restarts server on script change)
- add dev to json.package
-
npm run dev
- create router.js, export.module
- import into index.js
- edit index to add router(app);
- make a User Model with Mongoose with email and password
- create models folder + models/user.js
- import mongoose and Schema
- setup schema in model
- mongo installed
- on windows: C:\Program Files\MongoDB\Server\3.2\bin\mongo.exe
- start in new command window
- import mongoose in index.js
- setup DB in index.js
- confirm connection by viewing mongodb console for new connection listening
- Download robomongo, create connection
- make sure to restart mongodb to use robomongo
- create controllers/authentication.js
- add new authentication post in router.js
- update authentication controller with send
- check for success with postman in chrome(http://localhost:3090/signup)
- read in user if passed, check if email exists, if not: save
- req.body gets contents of req (request)
- in postman select Body -> raw and JSON
- add email and password info & test with console log (shos in server console))
- add user model into controllers/authentication
- fill out authentication controllers, connect to user model (mongoose)
- test in server console and postman
- add a check to verify email/password - make sure exists
-
npm install --save bcrypt-nodejs
- import bcrypt to user.js
- save, hook and encrypt password
- see diagram
-
npm install --save jwt-simple
- create config.js file with secret string
- import jwt-simple & config into authentication controller
- add tokenForUser function
- now edit res.json({token:tokenForUser(user)});
- addiitonal resources: https://jwt.io/
- Check login intercept with passport.js
-
npm install --save passport passport-jwt
- mkdir server\services & server\services\passport.js
- require 5 modules
- goals: create some jwt options, create jwt strategy, tell passport to use this strategy
- fill out jwtOptions - add jwtRequest to get string from the header
- secretOrKey: config.secret
- tell passport to use this strategy - passport.use(jwtLogin);
- make changes to router to require authorization on a certain route
- postman send GET http://localhost:3090/
- this part is a bit tricky... in postman signup with the POST http://localhost:3090/signup
- copy the token only (received after submitting)
- change to GET http://localhost:3090/ - add 2 lines to Headers (key:value)
- Content-Type: application/json .... authorization: [input the token copied]
- Different strategy, local data
-
npm install --save passport-local
- Add comparePassword method salt/password to user.js (6.82)
- Add comparePassword method to passport.js
- Bottom of passport.js, tell passport to use localStrategy
- Go to router to add POST to Signin
- authenticate.js export signin
- we need to get the current user model inside the signin function
- done - Postman check in postman, for testing - careful of typo (!user) vs (err) in passport.js
- POST sign up: http://localhost:3090/signup
- POST sign in: http://localhost:3090/signin
- GET (must include authorization/content-type json in header) authenticate for restricted resource: http://localhost:3090/
Based on auth server client-side in the Udemy course Advanced React
- Download ReduxSimpleStarter
-
npm install
-
npm run start
- http://localhost:8080/
- Route Wireframe image
- 5 routes - /, /signin, /signup, /feature, /signout
- Component diagram
- Application state diagram
- Add initial Route
- index.js: import { Router, Route, IndexRoute, browserHistory } from 'react-router';
- Route inside Provider -
- test: http://localhost:8080/
- Create Header component
- Make header.js - import Component & react, Header extends Component, export default Header
- app.js - add
- create auth folder - client\src\components\auth
- create signin.js component
-
npm install --save redux-form
- export default reduxForm(
- in signin.js import reduxForm
- in reducers/index import reducer from redux-form
- Tip, you can do this ("as form") in ES6 : import { reducer as form } from 'redux-form';
- this allows you change reducer to form: form (instead of form: reducer)
- this can be further refactored to just form (in ES6 with curly braces its same as form:form)
- set up sign in form in sign.js
- Add to signin.js - handleSubmit = this.props
- In signin.js - Add email and password helpers
- Listen for onSubmit
- make handleFormSubmit function
- import and hook up to App component so we can see the form.
- in app.js {this.props.children}
- check here: http://localhost:8080/signin
- enter user/pass and see it come up in console
- When submitting form we need to connect ti to the server
- We need an Action Creator with a callback to handle invalid submits, errors
- see: action-creator-form-flow.Protecting
- edit actions/index.js
- see: action-flow-full-diagram.png
-
npm install --save redux-thunk
- must import in src/index.js
- in index.js add to apply middleware chain
- normally - action creator always return an object, the object is an "action", and the action has a "type"
- however, with thunk - the action creator returns a function. (to get direct access to the dispatch method, allowing us to dispatch actions when we want)
- all logic for action creator can go inside the return function
- we'll be submitting email/password to api server
- startup api server (npm run start and mongod) running on port 3090
- in actions/index declare const ROOT_URL = 'http://localhost:3090/';
- to make the ajax request we'll use axios library
-
npm install --save axios
-
npm run start
- actions/index - add import and post.axios
- signin.js - import * as actions from '../../actions';
- signin.js - expor default reduxForm - add: ,null, actions to access to all actions on props.
- signin.js - this.props.signinUser({email, password});
- [in server dir] >npm install --save cors
- try again - http://localhost:8080/signin
- must be signing in with a previous user/email (check robomongo)
- check for token response in devconsole XHR > Response > JSON
- add then & catch to axios call in actions/index (promises)
- add programmatic navigation: redirect to link
- import { browserHistory } from 'react-router'; browserHistory.push('/feature')
- test to redirret to feature : http://localhost:8080/signin
- setup authReducer in reducers/index and auth_reducer.js
- add authenticate case and flags to auth_reducer
- add actions/types.js`
- good walkthough of the client code until now.
- saving the JWT token with the action creator - where? - LocalStorage
- LocalStorage code in actions/index
- check browser: http://localhost:8080/signin
- sign in and refresh page
- check Chrome console local storage: localStorage.getItem('token') - should show token
- add auth_error to types file
- make a new action creator authError in actions/index
- make sure to import type into actions/index file
- Add error to auth_reducer
- in signin.js add mapStateToProps
- signin.js: add Error msg renderAlert function
- obfuscate password field (input type)
- make header.js a container: import { connect } from 'react-redux';
- import Link
- add connect helper to export statement
- add mapStateToProps
- renderLinks method for which buttons to display
- (we also use an array of components for the signin and signout part)
- make sure to add keys in the component array, we use static keys
- test: http://localhost:8080/signin
- still have to do dome debugging
- Correct error in last section - add mapStateToProps in export connect helper
- create: client\src\components\auth\signout.js
- setup Signout component
- in src/index.js import signout.js, add route
- Action creator for Signout to finish Signout component
- types.js - make sure action type has ben specified, in this case UNAUTH_USER
- in actions/index import UNAUTH_USER
- make function called signoutUser
- we need to also get rid of the token we saved
- localStorage.removeItem('token');
- create signup.js
- Scaffold out Signup component
- Add import and route for Signup
- test: http://localhost:8080/signup
- Login scaffolding diagram (7.107)
- signup.js: export default reduxForm({
- Signup form with redux-form (7.107)
- Front-end of Signup form (7.107) email, password, passwordConfirm
- 2 stage validation.
- (1) Password entered that matches password validation clientside
- (2) Then send off to server
- ReduxForm maks validation easy on the client side
- ReduxForm-validation-flow.png
- on keypress user input goes to validation function as an object
- if error return object based on keypress
- if no error return empty object
- signup.js: function validate(formProps) {
- tell ReduxForm to use function
- test with console.log inside validate function
- set error conditions in validate function
- under each html field have a returned error msg
- to delay error msg until clicked out of input: add in password.touched before password.error (see full line)
- Add red text style for error
- make sure user has entered text for all fields
- show delayed msg using same method as in previous error msgs
- add handleSubmit to form tag
- setup handleFormSubmit helper under class - inside Call action creator
- edit action/index.js - signup action (axios.post) will be nearly identical to signin
- export signupUser
- we need to resolve the current error in console - this.props.signupUser is not a function
- we had forgottent to add to actions at the nottom of the file
- signup again check console to make sure (1) console error gone (2) network tab to show signup call made and (3) token recieved (click signup)
- Signup again and there should be an error with response Email in Users
- in actions/index - duplicate (mostly) the first axios promise (signin) for signup now except for error part
- gotcha - orginal said to use .catch(response... but you must use
.catch(error => { dispatch(authError(error.response.data.error)) }); - gotcha 2: make sure the displayed errors msg underthe button is encapsulated within a return();
- in signup - mapStateToProps
- now add mapStateToProps to export actions at bottom of signup
- add renderAlert() function to signup
- TEST: should be able to (1) signup with a an old email and get error under form, (2) signup with new email, get return token
- Clear out error messages: auth_reducer: error '',
- setup the feature route - feature could be whatever your main application page is
- 1 - scaffold component feature.js
- 2 - router: import Feature
- create: client\src\components\auth\require_auth.js
- copy all code from ReduxInitializer/src/components/require_authorization.js
- change state.authenticated to state.auth.authenticated
- import RequireAuth
- Then, any route that needs protected can just use ex.: {RequireAuth(Feature)}
- Add to route
- GOTCHA: make sure state.auth.authenticated (I previously switched auth in front)
- test: http://localhost:8080/
- at this point, eature can only be accessed after signup or on signin.
- set up index route
- Setup index route to Welcome component
- make new welcome.js file
- test: http://localhost:8080/
- in src/index.js - we're going to change around the store
- const store = createStoreWithMiddleware(reducers);
- const token = localStorage.getItem('token'); // if we have token, user is signed in
- if(token){ store.dispatch({ type: AUTH_USER })
- import AUTH_USER
- make action creator for API
- wire up to feature component
- add export to actions/index, including fetchMessage method with axios
- in feature.js add redux, connect and actions
- in feature.js add fetchMessage() in componentWillMount
- at this point in console we get a 401, and bounced to home page: http://localhost:8080/feature
- We need to get header to authenticate so next we'll add that in the axios call by puting an object after it.
- headers: { authorization: localStorage.getItem('token') }
- in types - create a new type FETCH_MESSAGE
- actions/index: import this type FETCH_MESSAGE into actions/index
- in action/index make use of redux thunk to dispatch type and payload
- in auth_reducer FETCH_MESSAGE
- in auth_reducer add case for FETCH_MESSAGE
- should return "secret message" from server - normally this would be protected data going to the user. http://localhost:8080/feature