sejr / swift-authentication

Swift Authentication helps you build secure authentication systems with Swift.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Swift Authentication

Swift

This Swift package provides a simple protocol-based interface for defining authentication mechanisms for a service.

At its foundation is the AuthenticationService protocol, copied here for convenience:

/// Functionality that enables a service to _authenticate_ a user.
///
/// Authentication is defined as verifying the identity of the user. This specifically does not include
/// functionality for determining which actions the user has _authorization_ for.
public protocol AuthenticationService {
    /// Information that can be used to verify the identity of a user.
    ///
    /// This information will generally have some security implications; you should ensure it is transmitted
    /// and stored (if necessary) in a secure fashion, using encryption and/or hashing. Those mechanisms are
    /// outside the scope of the Swift Authentication package.
    associatedtype Credential
    
    /// The result of a successful authentication request.
    associatedtype AuthenticationSuccess
    
    /// The result of a failed authentication request.
    associatedtype AuthenticationFailure: Error
    
    /// Authenticates a user based on some provided `Credential`.
    func authenticate(
        with credential: Credential,
        completion: @escaping (Result<AuthenticationSuccess, AuthenticationFailure>) -> Void
    )
}

Beyond this protocol, you are largely on your own. The goal of this project is to provide some common credential types, such as the UsernamePasswordCredential for basic username and password authentication.

Getting Started

Installation

Update your Package.swift file like so:

let package = Package(
    // name, platforms, products, etc.
    dependencies: [
        .package(url: "https://github.com/sejr/swift-authentication", from: "0.1.0"),
        // other dependencies
    ],
    targets: [
        .target(name: "<target>", dependencies: [
            "Authentication",
            // other dependencies
        ]),
        // other targets
    ]
)

Defining an authentication service

import Authentication

/// An example service.
///
/// Notice that this definition has nothing pertaining to authentication; we encapsulate all of that
/// information inside an extension.
class ExampleAuthenticationService {
    /// General notion of user identity within this example service.
    struct User {
        /// The unique ID for the user.
        var id: String
    }
    
    /// General error for this example service.
    enum ServiceError: Error {
        /// Invalid username and password combination.
        case invalidCredential
        
        /// Something else went wrong.
        case unknown
    }
}

extension ExampleAuthenticationService: AuthenticationService {
    typealias Credential = UsernamePasswordCredential
    typealias AuthenticationSuccess = User
    typealias AuthenticationFailure = ServiceError
    
    public struct ServiceCredential: UsernamePasswordCredential {
        var username: String
        var password: String
    }
    
    func authenticate(with credential: UsernamePasswordCredential, completion: @escaping (Result<ExampleAuthenticationService.User, ExampleAuthenticationService.ServiceError>) -> Void) {
        let validUsername = credential.username == "testing"
        let validPassword = credential.password == "testing"
        
        if (validUsername && validPassword) {
            completion(.success(ExampleAuthenticationService.User(id: credential.username)))
        } else {
            completion(.failure(.invalidCredential))
        }
    }
}

Building a credential

This step is largely dependent on how you have defined your credential. Because our ExampleAuthenticationService has defined a ServiceCredential type that conforms to UsernamePasswordCredential, it can be used like so:

let credential = ExampleAuthenticationService.ServiceCredential(
    username: "testing",
    password: "testing"
)

Authenticating the credential against the service

The AuthenticationService provides a single function, authenticate, which takes the credential type you've defined, and returns the result you've defined. It's pretty straight-forward, right?

service.authenticate(with: credential) { (result) in
    // Check result of authentication attempt
    switch result {
    case .success(let user):
        print(user.id)
    case .failure(let err):
        print(err)
    }
}

About

Swift Authentication helps you build secure authentication systems with Swift.


Languages

Language:Swift 100.0%