Skip to content

Latest commit

 

History

History
161 lines (128 loc) · 7.15 KB

BasicAuthentication.md

File metadata and controls

161 lines (128 loc) · 7.15 KB

Adding Basic authentication to Kitura FoodServer

Kitura Bird

Slack

Now that there is a FoodServer backend for the FoodTracker app, you can add HTTP basic authentication to the routes. This will allow your users to log in, have the server identify them and respond accordingly.

Pre-Requisites:

These instructions follow on from the FoodTracker application and server created by following the FoodTrackerBackend tutorial. If you have completed the FoodTracker Backend there are no further pre-requisites.

If you have not completed the FoodTrackerBackend tutorial go to the CompletedFoodTracker branch and follow the README instructions.

HTTP Basic authentication

HTTP Basic authentication transmits credentials in an “Authorization” header as base64 encoded user ID/password pairs. Kitura also allows you to send the username and password in the URL as follows:

https://username:[email protected]/

Note: some web browsers disable this for security reasons.

Add the Kitura-CredentialsHTTP dependency

Kitura-CredentialsHTTP is a Kitura-Credentials plugin that lets you perform HTTP basic authentication and needs to be added to our Package.swift file.

  1. In the terminal, go to your server's Package.swift file.
cd ~/FoodTrackerBackend/FoodServer
open Package.swift
  1. Add the Kitura-CredentialsHTTP package:
.package(url: "https://github.com/IBM-Swift/Kitura-CredentialsHTTP", from: "2.1.0"),
  1. Change the target for Application to include "CredentialsHTTP":
.target(name: "Application", dependencies: [ "Kitura", "CloudEnvironment", "SwiftMetrics", "Health", "SwiftKueryORM", "SwiftKueryPostgreSQL", "CredentialsHTTP"]),
  1. Regenerate your FoodServer Xcode project:
swift package generate-xcodeproj

Create the TypeSafeHTTPBasic struct

We will declare a struct which conforms to TypeSafeHTTPBasic. This will be initialized when our route is successfully authenticated and we will be able to access the authenticated user's id within our Codable route.

  1. Open the FoodServer Xcode project
open FoodServer.xcodeproj/
  1. Inside Sources > Application > Application.swift add CredentialsHTTP to your imports:
import CredentialsHTTP

Below the Persistence Class, define a public struct called MyBasicAuth that conforms to the TypeSafeHTTPBasic protocol:

public struct MyBasicAuth: TypeSafeHTTPBasic {

}
  1. Xcode should display the message:
Type 'MyBasicAuth' does not conform to protocol 'TypeSafeCredentials'

Click "Fix" to autogenerate the stubs below:

public static func verifyPassword(username: String, password: String, callback: @escaping (MyBasicAuth?) -> Void) {

}

public var id: String
  1. Inside MyBasicAuth, add an authentication dictionary:
public static let authenticate = ["username": "password"]
  1. The function, verifyPassword, takes a username and password and, on success, returns a MyBasicAuth instance. We want to check if the password matches the user's stored password. On successful match, we initialize MyBasicAuth with an id equal to username.
if let storedPassword = authenticate[username], storedPassword == password {
    callback(MyBasicAuth(id: username))
    return
}
callback(nil)

This function is async, so that you can perform async actions to verify the password, e.g. looking up the username and password in a database. You must call the callback closure with either an instance of 'Self' or 'nil' before exiting 'verifyPassword'. If you do not, the server will not know to continue and you will receive a 503 "Service Unavailable" error, when you call the route.

Your complete struct should now look as follows:

public struct MyBasicAuth: TypeSafeHTTPBasic {

    public static let authenticate = ["username": "password"]

    public static func verifyPassword(username: String, password: String, callback: @escaping (MyBasicAuth?) -> Void) {
        if let storedPassword = authenticate[username], storedPassword == password {
            callback(MyBasicAuth(id: username))
            return
        }
        callback(nil)
    }

    public var id: String
}

Adding Basic Auth to the routes

MyBasicAuth is a Type-safe middleware and can be registered to a Codable route by adding it to the handler signature.

Add auth: MyBasicAuth to the completion closure in the storeHandler signature.

func storeHandler(auth: MyBasicAuth, meal: Meal, completion: @escaping (Meal?, RequestError?) -> Void ) {

Add auth: MyBasicAuth to the completion closure in the loadHandler signature.

func loadHandler(auth: MyBasicAuth, completion: @escaping ([Meal]?, RequestError?) -> Void ) {

Add auth: MyBasicAuth to the completion closure in the summaryHandler signature.

func summaryHandler(auth: MyBasicAuth, completion: @escaping (Summary?, RequestError?) -> Void ) {

These routes now require basic authentication. You can test this by running the server and going to http://localhost:8080/summary.

The request will be rejected as unauthorized and your browser will offer a window for you to input the username and password.

Enter "username" and "password" to be allowed to view the route or any other combination to have the request rejected.

The browser will store correct credentials so use a private window if you want to test rejected credentials.

Congratulations!!! You have just added HTTP basic authentication to your Kitura server.

Sending credentials from your mobile app

You need to enable your food tracker mobile application to send the username and password so that it can continue to connect to your now protected routes. You can do this by setting the default credentials on the KituraKit client as shown below.

  1. Open the FoodTracker workspace:
cd ~/FoodTrackerBackend/iOS/FoodTracker/  
open FoodTracker.xcworkspace
  1. Open the FoodTracker > MealTableViewController.swift file
  2. Add default credentials inside the saveToServer function to be used by the client:
client.defaultCredentials = HTTPBasic(username: "username", password: "password")

This will add the credentials to all your KituraKit requests.

  1. You could also add credentials on individual routes as follows:
client.post("/meals", data: meal, credentials: HTTPBasic(username: "username", password: "password"))

However that is not required for this example.

Now your Foodtracker app and server will be able to send and receive requests using basic authentication!