Two-Factor Authentication With Vapor

Learn how to increase the account security of your using two-factor authentication with Vapor. By Jari Koopman.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Getting Middleware Working

Now it’s time to connect the dots and get the middleware working. In 2FAToken.swift, conform TwoFactorToken to OTPToken. The required validate(_:allowBackupCode:) function is already implemented, so no further action is necessary.

Next, in User.swift, find the extension conforming User to ModelAuthenticatable. Replace the entire extension with the following:

extension User: TwoFactorAuthenticatable {
  // 1
  static let usernameKey = \User.$username
  static let passwordHashKey = \User.$passwordHash
  // 2
  static let twoFactorEnabledKey = \User.$twoFactorEnabled
  static let twoFactorTokenKey = \User.$twoFactorToken

  // 3
  func verify(password: String) throws -> Bool {
    try Bcrypt.verify(password, created: self.passwordHash)
  }
}

This will conform User to TwoFactorAuthenticatable as follows:

  1. First, keep the properties required by ModelAuthenticatable, since TwoFactorAuthenticatable extends it.
  2. Second, add the properties specific to TwoFactorAuthenticatable. For the twoFactorEnabledKey, use the $twoFactorEnabled Fluent field, and for twoFactorTokenKey, use the $twoFactorToken field.
  3. Finally, implement ModelAuthenticatable‘s verify for basic password authentication.

Because of the magic of Swift, all routes previously using User‘s ModelAuthenticatable feature set now automatically also get the 2FA protection.

As the final step, in UserController.swift in boot(boot:), revert the login route to use the original login handler again, instead of loginWithTwoFactor. The latter is no longer required since the middleware will handle it now.

With everything set up, build and run the app and open Postman or Paw. Again, find the Login request and execute it. If your previous OTP is still in the headers, it should respond with 401 Unauthorized. Before putting in a valid OTP, remove the header and make sure the API returns 206 Partial Content.

Now, put in a valid OTP and the API should once again give back a token — this time, without the UserController even knowing about 2FA. Awesome!

Where to Go From Here?

You can download the final project using the Download Materials button at the top or bottom of this page.

In this tutorial, you learned about creating one-time passwords, added 2FA to your app and extracted 2FA into reusable middleware. Great job!

To learn more about the cryptography behind OTPs, you can read about HMAC, SHA-1 and SHA-2 on Wikipedia.

We hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below!