Chris on Code
This tutorial is out of date and no longer maintained.
Note: This article is part of our Easy Node Authentication series.
This will be the final article in our Easy Node Authentication Series. We will be using all of the previous articles together.
Note: Edit 11/18/2017: Updated to reflect Facebook API changes.
This article will combine all the different Node Passport Strategies so that a user will be able to have one account and link all their social networks together.
There are many changes that need to take place from the previous articles to accomplish this. Here are the main cases we have to account for when moving from authenticating with only 1 account versus multiple accounts.
We’ll be going through each of these scenarios and updating our previous code to account for them.
We’ll be working with the Local Strategy and the Facebook Strategy to demonstrate linking accounts. The tactics used for the Facebook Strategy will carry over to Twitter and Google.
In order to add linking accounts to our application, we will need to:
When looking at the way we set up our user model, we deliberately set up all the user accounts to be set up within their own object. This ensures that we can link and unlink different accounts as our user sees fit. Notice that the social accounts will use token
and id
while our local account will use email
and password
.
We have also added in email
, name
, displayName
, and username
for some accounts just to show that we can pull that information from the respective social connection.
Once a user has linked all their accounts together, they will have one user account in our database, with all of these fields full.
When we originally made these Strategies, we would use passport.authenticate
. This is what we should be using upon first authentication of our user. But what do we do if they are already logged in? They will be logged in and their user stored in session when we want to link them to their current account.
Luckily, Passport provides a way to “connect” a user’s account. They provide passport.authorize
for users that are already authenticated. To read more on the usage, visit the Passport authorize docs.
We will update our routes to handle the authorization first, and then we’ll update our Passport Strategies to handle the authorization.
Let’s create our routes first so that we can see how we link everything together. In the past articles, we created our routes for authentication. Let’s create a second set of routes for authorization. Once we’ve done that, we’ll change our Strategy to accommodate the new scenarios.
Our old routes will be commented to make a cleaner file.
As you can see, we have all the authentication routes and the routes to show our index and profile pages. Now we have added authorization routes which will look incredibly similar to our authentication routes.
With our newly created routes, let’s update the Strategy so that our authorization routes are utilized.
We will just update the Facebook and Local Strategies to get a feel for how we can accommodate all our different scenarios.
When using the passport.authorize
route, our user that is stored in session (since they are already logged in) will be passed to the Strategy. We will make sure we change our code to account for that.
We’re going to show the old Strategy and then the new Strategy. Read the comments to get a full understanding of the changes.
Now we want the ability to authorize a user.
Now we have accounted for linking an account if a user is already logged in. We still have the same functionality from before, now we just check if the user is logged in before we take action.
Using this new code in our Strategy, we will create a new user if they are not already logged in, or we will add our Facebook credentials to our user if they are currently logged in and stored in session.
Other Strategies: The code for the Facebook Strategy will be the same for Twitter and Google. Just apply that code to both of those to get this working. We will also provide the full code so you can look at and reference it.
Now that we have the routes that will pass our user to our new Facebook Strategy, let’s make sure our UI lets our user use the newly created routes.
We will update our index.ejs
and our profile.ejs
to show all the login buttons on the home page, and all the accounts and link buttons on the profile page. Here is the full code for both with the important parts highlighted.
Now we will have the links to each of our login methods. Then after they have logged in with one, the profile will check which accounts are already linked and which are not.
If an account is not yet linked, it will show the Connect Button. If an account is already linked, then our view will show the account information and the unlink button.
Remember that our user is passed to our profile view from the routes.js
file.
Our social accounts can easily be configured this way. The only problem currently is if a user wanted to connect to a local account. The problem comes in because they will need to see a signup page to add their email and password.
We have already created a route to handle showing our new connection form (in our routes.js
file: (app.get('connect/local'))
). All we need to do is create the view that the route brings up.
Create a file in your views folder: views/connect-local.ejs
.
This will look incredibly similar to our signup.ejs
form. That’s because it really is. We pretty much just changed out the verbiage and the action
URL for the form.
Now when someone tries to connect a local account, they will be directed to this form, and then when submitted, they will be directed to our Local Strategy. That links the accounts!
With just those routes and the update to our Passport Strategies, our application can now link accounts together! Take a look at a user in our database that has all their accounts linked using Robomongo:
Linking accounts was easy. What about unlinking? Let’s say a user no longer wants their Facebook account linked.
For our purposes, when a user wants to unlink an account, we will remove their token
only. We will keep their id
in the database just in case they realize their mistake of leaving and want to come back to join our application.
We can do this all in our routes file. You are welcome to create a controller and do all this logic there. Then you would just call the controller from the routes. For simplicity’s sake, we’ll throw that code directly into our routes.
Let’s add our unlinking routes after our newly created authorization routes.
In these routes, we just pull a user’s information out of the request (session) and then remove the correct information. Since we already had created our links to these routes in profile.ejs
, they will now work since we have created the routes finally.
Now you can link an account and unlink an account.
When trying to unlink, we will have to do a little more configuration for that to work. Since the id
is already stored in the database, we will have to plan for that scenario when a user links an account that was already previously linked.
After a user is unlinked, their id
still lives in the database. Therefore, when a user logs in or relinks an account, we have to check if their id
exists in the database.
We will handle this in our Strategy. Let’s add to our Facebook Strategy.
Now just add that same code across the board to all of our Strategies and we have an application that can register a user, link accounts, unlink accounts, and relink accounts.
For those interested in seeing the entire code altogether, make sure you check out the GitHub repo. Also, here are direct links to the two most important files:
Hopefully, we covered most of the cases that you’ll run into when authenticating and authorizing users. Make sure to take a look at the full code and the demo to make sure that everything is working properly. If you see anything that raises questions, just let me know and be sure to go look at the full code for clarification!
Thanks for sticking with us throughout this entire series. We hope you enjoyed it. We’ll be expanding on authentication further in the future by doing a Node and Angular authentication tutorial. Until then, happy authenticating!
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!