Skip to content

Commit

Permalink
Merge branch 'main' into swift-6
Browse files Browse the repository at this point in the history
  • Loading branch information
Firehed committed Jul 31, 2024
2 parents cb7e5e6 + 6a8e561 commit 744d1c7
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 13 deletions.
7 changes: 7 additions & 0 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Swift Package Index
version: 1
builder:
configs:
- documentation_targets:
- SnapAuth
platform: ios
32 changes: 22 additions & 10 deletions Sources/SnapAuth/Errors.swift
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
import AuthenticationServices

/// SnapAuth error codes
///
/// Authentication and credential registration can fail or be rejected in
/// numerous ways, and applications should be prepared to handle these
/// scenarios.
public enum SnapAuthError: Error {
/// The network request was disrupted. This is generally safe to retry.
case networkInterruption

/// A new request is starting, so the one in flight was canceled
/// Only a single request can run at a time. A new request is starting, so
/// the current one is being canceled.
case newRequestStarting

/// This needs APIs that are not supported on the current platform
/// This needs APIs that are not supported on the current platform. You can
/// use `if #available()` conditionals, or similar, to avoid this.
case unsupportedOnPlatform

// MARK: Internal errors, which could represent SnapAuth bugs

/// The SDK received a response from SnapAuth, but it arrived in an
/// unexpected format. If you encounter this, please reach out to us.
/// unexpected format.
///
/// If you encounter this, please reach out to us.
case malformedResposne

/// The SDK was unable to encode data to send to SnapAuth. If you encounter
/// this, please reach out to us.
/// The SDK was unable to encode data to send to SnapAuth.
///
/// If you encounter this, please reach out to us.
case sdkEncodingError

/// The request was valid and understood, but processing was refused. If you
/// encounter this, please reach out to us.
/// The request was valid and understood, but processing was refused.
///
/// If you encounter this, please reach out to us.
case badRequest

// MARK: Weird responses

/// ASAuthorizationServices sent SnapAuth an unexpected type of response
/// which we don't know how to handle. If you encounter this, please reach
/// out to us.
/// `ASAuthorizationServices` sent SnapAuth an unexpected type of response
/// which we don't know how to handle.
///
/// If you encounter this, please reach out to us.
case unexpectedAuthorizationType

/// Some of the data SnapAuth requested during credential registration was
Expand Down
84 changes: 84 additions & 0 deletions Sources/SnapAuth/SnapAuth.docc/SnapAuth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# ``SnapAuth``

The official [SnapAuth](https://www.snapauth.app) SDK for Apple platforms.

## Overview

SnapAuth allows you to quickly, easily, and reliably add passkeys to your web and native apps.
You can be up and running in minutes on all platforms without ever having to look at `AuthenticationServices`.

This SDK supports all native Apple platforms that permit passkey use - iOS, iPadOS, macOS, visionOS, and tvOS.
Apple Watch and watchOS do not support passkeys.
If and when it does, we'll add support as well.

## Getting Started

To use SnapAuth, you'll first need to register an account: [](https://www.snapauth.app/register).
Registration is free, but SnapAuth is a paid service and you'll be limited to a small number of users during the free trial.

Once you register, you'll be taken to our [dashboard](https://dashboard.snapauth.app).
In there, you can get access to your `publishable key`, which you'll need to use SnapAuth in your native app.

## Topics

### Setup

To start, import the SnapAuth SDK and provide it your _publishable key_ from the dashboard.

```swift
import SnapAuth

let snapAuth = SnapAuth(publishableKey: "pubkey_your_key")
```

- ``SnapAuth/SnapAuth``
- ``SnapAuth/SnapAuth/init(publishableKey:urlBase:)``

### Credential Registration

Create a new passkey (or associate a hardware key) for the user.

- ``SnapAuth/startRegister(name:displayName:authenticators:)``

### Authentication

Authenticate a user using their previously-registered passkey or hardware key.

- ``SnapAuth/SnapAuth/startAuth(_:authenticators:)``
- ``SnapAuth/AuthenticatingUser``

### Credential AutoFill

When a user focuses a `TextField` with `.textContentType(.username)`, the QuickType bar can suggest passkeys.
This allows the user to authenticate without even having to fill in their username.

AutoFill is only available on iOS and visionOS.

- ``SnapAuth/SnapAuth/handleAutoFill()``

### Controlling Authenticator Types

For the best user experience and most flexibility, allow all of the platform's supported authenticators.
Passkeys are supported on all platforms.
External hardware authenticators are not supported on tvOS or visionOS.

- ``SnapAuth/SnapAuth/Authenticator``

### Handling Responses

All of the SDK's core methods will return a `SnapAuthResult`, which is an alias for `Result<SnapAuthTokenInfo, SnapAuthError>`.
Inspect the result to decide how to proceed.

```swift
let result = await snapAuth.startAuth(.id("usr_123456"))
switch result {
case .success(let auth):
// Send auth.token to your backend to sign in the user
case .failure(let error):
// Examine the error and decide how best to proceed
}
```

- ``SnapAuth/SnapAuthResult``
- ``SnapAuth/SnapAuthTokenInfo``
- ``SnapAuth/SnapAuthError``
6 changes: 4 additions & 2 deletions Sources/SnapAuth/SnapAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ public class SnapAuth: NSObject { // NSObject for ASAuthorizationControllerDeleg

internal var continuation: CheckedContinuation<SnapAuthResult, Never>?

/// Initialize the SnapAuth SDK
/// - Parameters:
/// - publishableKey: Your SnapAuth publishable key. This can be obtained
/// from the [SnapAuth dashboard](https://dashboard.snapauth.app)
/// - urlBase: A custom URL base for the SnapAuth API. This is generally
/// for internal use.
/// - urlBase: A custom URL base for the SnapAuth API. This should usually
/// be omitted and left as the default value.
public init(
publishableKey: String,
urlBase: URL = URL(string: "https://api.snapauth.app")!
Expand Down Expand Up @@ -224,6 +225,7 @@ public class SnapAuth: NSObject { // NSObject for ASAuthorizationControllerDeleg
}
}

/// A representation of the user that is trying to authenticate.
public enum AuthenticatingUser: Sendable {
/// Your application's internal identifier for the user (usually a primary key)
case id(String)
Expand Down
13 changes: 12 additions & 1 deletion Sources/SnapAuth/SnapAuthDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import Foundation

/// The success case of adding or using a passkey.
///
/// `SnapAuthTokenInfo` is the result of a successful authentication or credential registration.
///
/// This holds a short-lived token which should be sent to your application's backend for verifcation and use.
///
/// The token on its own does not authenticate a user; instead, the token must be sent to your application's backend for processing and verification.
/// Tokens are short-lived and one-time-use.
///
/// See our [server documentation](https://docs.snapauth.app/server.html) for additional info on how to use these tokens.
public struct SnapAuthTokenInfo {
/// The registration or authentication token.
///
Expand All @@ -10,9 +20,10 @@ public struct SnapAuthTokenInfo {

/// When the paired token will expire.
///
/// If you try to use it after this time (or more than once), the request
/// If you try to use it after this time, or more than once, the request
/// will be rejected.
public let expiresAt: Date
}

/// An alias for the native `Result` type with our success and failure states.
public typealias SnapAuthResult = Result<SnapAuthTokenInfo, SnapAuthError>

0 comments on commit 744d1c7

Please sign in to comment.