Social Authentication in Vapor 1

Caleb Kleveter
The Swift Web Developer

--

Note: This article is not compatible with Vapor 2. If you are still on Vapor 1, you can follow this tutorial.

Working off of my last post here, we will be implementing user authentication using Facebook and Google. If you don’t have the old project, you can get it on this GitHub repo.

The set up is already done for us, so we just need to implement the methods into our User class.

Start by adding facebookID and googleID variables. They should be of the String type:

There are some classes such as GoogleAccount and FacebookAccount that we need to access for logging in a user with their accounts. To get these classes we need to import TurnstileWeb:

Change the password variable to be preset to an empty string. We want to do this because when we create a user with their Facebook or Google account, we won’t be using a password.

Next we need to add initializers for these variables using the GoogleAccount and FacebookAccount classes. They implement the Credentials protocol, so they work like the UsernamePassword class:

We also need make sure we update the makeNode() and init(node: Node, in context: Context) for these properties:

Now, all we have left to do is add the additional cases to the authenticate and register methods. We’ll start with register.

The way we have it setup right now is not very customizable. Let’s change it to use a switch statement for each supported credentials type. We will throw an Abort error if the type is un-supported.

Now we will add cases to the register method for FacebookAccount and GoogleAccount credential types. To do this we will do two things:

  1. If the user exists, return it, else
  2. Create a new user and return it.

Here is the final method:

Next, we will move onto the authenticate method. We already used a switch in this method, so we don’t need to refactor first. What we will do is simply check to see if the user exists. If it does, then return the user, else we’ll abort.

Here are the cases:

So your method should look like this when you are done:

We know have the User class ready for business. However, to login with Facebook or Google, we still need to setup a couple of routes in the LoginController.

We will start by creating some environment variables for the application IDs and Secrets. To do this, you will need to have registered the app with Facebook and Google Then, run the following commands in the command line. This will create variables on your machine called environment variables that you can access anywhere:

Then, we will get access to them by link to the variables in Config/app.json*:

Now, go to LoginController.swift. Import TurnstileWeb to LoginController.swift. We need this so we can access the Facebook and Google classes. We also need to import TurnstileCrypto so we can create a token, using URandom, to pass along to Facebook or Google when we login a user.

In the addRoutes(drop) method, add the following code. This gets that variables from app.json that we just created:

Now we can create an instance of the Facebook class from the ID and Secret keys we just accessed:

Before we create our necessary routes, we will create a helper property for the Request class that returns the hostname, scheme, and port in a URL string form. This is so we redirect back to the correct page after the user logs in on Google or Facebook.

Create a new file called Request+VaporAuth.swift in the Models folder. Then add the code below:

As I explained before, this computed property returns the current hostname, scheme, and port in a URL string form. Now we can create the necessary routes.

For the first route, follow the steps below:

  1. Create the function using a closure. Set the URL to login/facebook.
  2. Create a state from a random secure token. This is used for validating the user after he/she logs in on Facebook and they are redirected back to your site.
  3. Create response with the state and the URL that you will redirect to after the login occurs.
  4. Add the state to the request’s cookies dictionary with the key “OAuthState”
  5. Return the response.

This is the route you link to in a web page so the user can login.

The second route is what you redirect to after the user logs in. Here are the steps to create the route:

  1. Create the function using a closure. Set the URL to login/facebook/consumer.
  2. Get the state from the request’s cookies dictionary with the key “OAuthState”.
  3. Get the Credentials from the URL callback and state and cast it to the type FacebookAccount.
  4. Login the user.
  5. Redirect to the desired page

That is it! To implement authentication with Google, you do almost exactly the same thing. This is the code you would add to the addRoutes(drop) method.

That’s it! Here is the final project on GitHub.

Because environment vars are not passed onto the server when you push your project to it, you will need to set them on the server also. To do that on Heroku, you can use the following command:

If you don’t want to mess with JSON, you can import Settings and use Env.get(<VAR-NAME>) to access the environment vars in Swift.

Thanks to Edward Jiang for all his help on this topic and allowing me to use the Vapor Turnstile Example!

Subscribe to Swift Web Weekly!

If you’re interested in web development with Swift, Swift Web Weekly is a free newsletter Gianluca Tranchedone is curating with interesting links related to server-side Swift, HTML, CSS, JavaScript, tools and more. If you don’t like it you can unsubscribe at any time, so why don’t give it a try?! 🙂

--

--

Caleb Kleveter
The Swift Web Developer

iOS and Vapor Fanatic. Has lots of fun open sourcing on GitHub.