WORKSHOP GOALS
1 - authenticate users: make users login locally or through a third party
2 - authorize users for certain resources
3 - understand the codebase well enough to accomplish these things
goal: to go through the workshop in the most intuitive way
goal: to understand the sessions and passport configurations necessary to keep a user logged in
STARTING POINT:
1. already have a signup controller and login controller that use auth factory methods to post data to the db
2. I've already set up the auth router to receive these requests
3. so now I have to do sessions
GOAL: server-side sessions to persist user data between a server and client across multiple requests (keep user logged in);
1. each session is particular to a given client—even across requests
2. a session will be a JavaScript object living in the runtime of our server.
3. This session object will contain data about a particular client—something we have so far been unable to do.
4. Sessions have no inherent understanding of "users"—they are simply a means to persist data across many different request/response cycles between the same server and client.
In server/app/Index.js: This middleware will give you access to a req.session object for any middleware that is downstream of it. Editing this object will edit it for all subsequent requests from the same client.
and I can use the session info anywhere after the requestState stuff so lets put it right below it
so now i'll have a session object any time a user makes a request for the index html page
1. a session will be a JavaScript object living in the runtime of our server.
2. this session object lives in a larger sessions hash
3. Anytime we restart our app, all of the user sessions are lost.
In server/app/Index.js:
the secret encrypts / hash the session id so that it isn't guessable
we have access to req.session in any middleware the is downstream of this hashing middleware, including our auth router. so now we can use sessions in login and signup
add user to session in auth login controller:
and this has to be session.userId because id is protected on the session obj (a read only property) because it is the primary key so we can't assign to it
in server/app/index.js:
we can add this to the signup controller in our auth router as well
by adding the user id to the session object of a user that just signed up, we're essentially logging them in
ADD LOGOUT functionality to factory and auth router
add isLoggedIn functionality to navbar directive
so now we can create functions that will help us manage state for the navbar : we need to create this getCurrentUser function
add getCurrentUser to Auth factory
modify navbar html
so now when I log in, only logout should appear
but what happens if I refresh? the currentUser disappears so I see the wrong buttons again
so I need to find a way to manage the currentUser state even when a user logs in
add refreshCurrentUser to the auth factory
app.run in main.js
run blocks: this will run on refresh every time. so on refresh we re-retrieve the user and set it to currentUser so we can maintain that state
in a config step you have access to providers and providers are slightly different from factories, they're like pre-built factories (it's like saying before you boot this app, change this factory just a little bit ; so they're configurable factories )
in a run state, we can't configure factories anymore
add user/me route to user controller
(uses router.params)
so now refresh should work
PART 2: now for google oauth: we need to make the google button work
1. when you click the button we want to send a request to google, so we need to do a reload so that we hit this route on the backend
and then route that request to a script that will handle google oauth by mounting it in our auth router. so add to our auth router
PART 2:
so now we create a google oauth script
so without worrying about the config just yet, we know from the lecture that we'll need 2 routes:
1) a route that handles the request for logging into google (when a user clicks the sign in via google button)
2) and a callback route that google will use to redirect that user once that user has authenticated
the whole point of the authenticate('google') is to tell passport to use the google strategy we are about to configure
- done function passes our data on to passport so that it can associate the user document with a session
- configuring a new google strategy for passport to use
- so the done function is so that we can tell passport when we're done doing what we want to do
- clientSecret is the password
find the user or create it
so that passport can associate the user with the session
using methods provided by passport-session:
1. passport initialize: adds methods to the req object that will be accessible in all the middleware downstream of it
2. the passport.session: will talk to other session middleware and use req.session for us
so associateWithSession won't quite work yet. we still need to do some stuff in app/index for this to work.
passport serializeUser: receives the user doc and done. we need to tell it what data to associate a user with a session: the id of the user.
associateWithSession from googleOauth triggers passports serializeUserFunction
deserializeUser needs to look up the user with the info we passed to it in serializeUser so that it can attach that user to the req object
the req.user object that passport gives us
we can now inspect this object
does anyone have an idea about what middleware is responsible for providing us with this req.user object ?
attachThisToTheSessionSomehow runs once when the user logs in via passport
associateWithSession from googleOauth triggers passports serializeUserFunction
to which we passed the user document that our anonymous fn has access to
but neither of these is express middleware. and the question is: what express middleware is responsible for providing us with the req.user object?
1. passport.initialize: gives us method on the req object
2. passport.session: looks up the deserializeUser function and the piece of info associated with the session and say req.user equals the object looked up
so now we don't have to work with the session directly anymore. because passport handles that for us
so now let's figure out how to only user passport for managing sessions because we still have req.session.userId in our code
so we do this now
so we do this now
now change the get me router to use req.user
Performance considerations:
we should put the passport initialize and session middleware beneath the statics middlware to reduce num of requests
Overview: what's the order of operations
1. clicking sign in with google (clicking this link takes them to auth/google which, because of code we have in the main.js, reloads the entire page, which triggers a backend request to /auth/google
2. and we handle the /auth/google request in the google oauth router. (router.get('/', passport.authenticate...)
3. passport.authenticate redirects us to google login page
4. user signs in to google
5. signing in triggers a request to google and google redirects us to the callback url --- /auth/google/callback because that's what we told it to do
6. we handle this in the router.get('/callback'...) middleware which triggers our whenDataComeBackFromGoogle callback which looks up the user or creates the user
7. then we call associateWithSession callback which triggers the serialization
8. the serialization takes care of the associate and then the successRedirect triggers - makes a request for /stories and the server serves up index.html
9. app.run makes a request for current user
10. for all subsequent request, deserializeUser runs. every time we make a request, we attach the user document to the request object