Skip to content

Effortlessly perform client certificate authentication in Swift to keep your server secure

License

Notifications You must be signed in to change notification settings

julianschiavo/LetMeIn

Repository files navigation

🔓 LetMeIn

LetMeIn is a mini Swift Package that performs client certificate authentication on network requests. Client certificate authentication (CCA) allows servers to authenticate that the client is legitimate and authorized to access the server, or API.

An example of this is Cloudflare's new API Shield feature, which makes it easy to require CCA to access an API, allowing you to create a private API for your app and prevent it from being abused outside your app.

This package is heavily inspired by and adapted from Jeroen's great blog post on CCA in Swift.


Requirements

LetMeIn requires iOS 14+ or macOS 11+. No other dependencies are required.


Installation

You can use LetMeIn as a Swift Package, or add it manually to your project.

Swift Package Manager (SPM)

Swift Package Manager is a way to add dependencies to your app, and is natively integrated with Xcode.

To add LetMeIn with SPM, click FileSwift PackagesAdd Package Dependency..., then type in the URL to this Github repo. Xcode will then add the package to your project and perform all the necessary work to build it.

https://github.com/julianschiavo/LetMeIn

Alternatively, add the package to your Package.swift file.

let package = Package(
    // ...
    dependencies: [
        .package(url: "https://github.com/julianschiavo/LetMeIn.git", from: "1.0.0")
    ],
    // ...
)

See SPM documentation to learn more.

Manually

If you prefer not to use SPM, you can also add LetMeIn as a normal framework by building the Xcode project from this repository. (See other sources for instructions on doing this.)


Usage

Create an instance of an authenticator, then use it as the delegate when performing URLSession requests.

// Create a certificate file representation
let certificate = CertificateFile(fileName: "certificate", password: "12345678")
// Create an authenticator
let authenticator = ClientCertificateAuthenticator(certificateFile: certificate)

// Make a custom URLSession using the authenticator as the delegate
let urlSession = URLSession(configuration: .default, delegate: authenticator, delegateQueue: nil)

// Perform a URL request
let request = URLRequest(url: ...)
urlSession.downloadTask(with: request) { (_, response, error) in
    ...
}

If you already have a custom URLSessionDelegate, or want to use this package in some other way (for example, with Alamofire), you can use the authenticator object directly. This is a more advanced technique, and used internally by LetMeIn to provide AVAsset support.

// Create a certificate file representation
let certificate = ...
// Create an authenticator
let authenticator = ...

// A `URLAuthenticationChallenge` that was received by your client
let challenge = ...

authenticator.handleChallenge(authenticationChallenge) { result, credential in
    switch result {
    case .cancelAuthenticationChallenge, .rejectProtectionSpace:
        challenge.sender?.cancel(challenge)
    case .useCredential:
        guard let credential = credential else { return }
        challenge.sender?.use(credential, for: challenge)
    case .performDefaultHandling:
        challenge.sender?.performDefaultHandling?(for: challenge)
    }
}

Examples

For example, to prevent other clients or browsers from accessing your content and resources, you can use LetMeIn together with SDWebImage to load images with a client certificate.

// Create a certificate file representation
let certificate = CertificateFile(fileName: "certificate", password: "12345678")
// Create an authenticator
let authenticator = ClientCertificateAuthenticator(certificateFile: certificate)

// Create a custom downloader operation (see SDWebImage documentation for more info)
class MyDownloaderOperation: SDWebImageDownloaderOperation {
    override func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        authenticator.urlSession(session, didReceive: challenge, completionHandler: completionHandler)
    }

    override func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        authenticator.urlSession(session, task: task, didReceive: challenge, completionHandler: completionHandler)
    }
}

// Make SDWebImage use our custom downloader operation when downloading images
SDWebImageDownloader.shared.config.operationClass = MyDownloaderOperation.self

// Load an image using SDWebImage
imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))

Contributing

Contributions and pull requests are welcomed by anyone! If you find an issue with LetMeIn, file a Github Issue, or, if you know how to fix it, submit a pull request.

Please review our Code of Conduct and Contribution Guidelines before making a contribution.


Credit

LetMeIn was created by Julian Schiavo, and available under the MIT License. Some code adapted from Jeroen's blog post on CCA in Swift.


License

Available under the MIT License. See the License for more info.

About

Effortlessly perform client certificate authentication in Swift to keep your server secure

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Languages