Two-Factor Authentication With Vapor
Learn how to increase the account security of your using two-factor authentication with Vapor. By Jari Koopman.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Two-Factor Authentication With Vapor
30 mins
- Getting Started
- Understanding Two-Factor Authentication
- Hash Based One Time Passwords
- Time Based One Time Passwords
- Setting up 2FA
- OTP Tokens
- Generating OTP Tokens
- Retrieving OTP Tokens
- Validating OTP Tokens
- Adding the Migrations
- Setting up the Handshake
- Testing the Handshake
- Logging in With a 2FA Token
- Extracting 2FA Into Middleware
- Implementing Middleware
- Getting Middleware Working
- Where to Go From Here?
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:
- First, keep the properties required by
ModelAuthenticatable
, sinceTwoFactorAuthenticatable
extends it. - Second, add the properties specific to
TwoFactorAuthenticatable
. For thetwoFactorEnabledKey
, use the$twoFactorEnabled
Fluent field, and for twoFactorTokenKey, use the$twoFactorToken
field. - Finally, implement
ModelAuthenticatable
‘sverify
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!