Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let package = Package(
targets: ["TSAuthenticationSDK", "TSAuthenticationSDK-Dependencies"])
],
dependencies: [
.package(url: "https://github.com/TransmitSecurity/core-ios-sdk.git", from: "1.0.31")
.package(url: "https://github.com/TransmitSecurity/core-ios-sdk.git", from: "1.1.5")
],
targets: [
.binaryTarget(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: Changelog
toc:
maxDepth: 2
---
# iOS Authentication SDK Changelog

## Authentication - 1.2.1 - May 2026
* feat: New security types for TOTP generation - 'devicePin' and 'devicePinOrBiometric'.
* feat: Added 'nativeBiometricsStatus()' API to retrieve the current native biometrics availability and status on the device.
* feat: Added 'nativeBiometricsType()' API to determine the currently available biometric authentication type (e.g., Face ID or Touch ID).
* feat: Enhanced iOS native biometrics error handling.

## Authentication - 1.2.0 - Feb 2026
* feat: Swift 6 support.

## Authentication - 1.1.17 - Dec 2025
* feat: Added compatibility with TSCoreSDK version 1.0.36.

## Authentication - 1.1.16 - Oct 2025
* feat: Add support PIN deletion.

## Authentication - 1.1.15 - May 2025
* feat: Add support PIN authentication.

## Authentication - 1.1.14 - Apr. 2025
* feat: Support elliptic-curve (EC) keys for mobile biometrics.
* feat: Allow multiple mobile-biometric registrations.

## Authentication - 1.1.13 - Apr. 2025
* feat: Add API for signing challenge using the device key.
* feat: Add APIs for client-side WebAuthn authentication, registration, and approval.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#if 0
#elif defined(__arm64__) && __arm64__
// Generated by Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
// Generated by Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
#ifndef TSAUTHENTICATIONSDK_SWIFT_H
#define TSAUTHENTICATIONSDK_SWIFT_H
#pragma clang diagnostic push
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,27 @@ public struct TSAuthenticationConfiguration {
}

public enum TSTOTPSecurityType: Codable {
/**
/**
Securing the secret with biometric authentication, adding an extra layer of security.
*/
case biometric
/**
No additional protection for secret
*/
case none
/**
Securing the secret with the device PIN or password.
The system passcode prompt is shown before generating a TOTP code.
*/
case devicePin
/**
Securing the secret with either device PIN or biometric authentication.
The system authentication prompt (biometrics with passcode fallback) is shown before generating a TOTP code.
*/
case devicePinOrBiometric
}

public struct TSDeviceInfo: Codable {
public struct TSDeviceInfo: Codable, @unchecked Sendable {
public let publicKeyId: String

public let publicKey: String
Expand All @@ -83,9 +93,8 @@ protocol TSBaseAuthenticationSdkProtocol {
static func isWebAuthnSupported() -> Bool
}

final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol, TSLogConfigurable {
final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol, TSLogConfigurable, @unchecked Sendable {


public static let shared: TSAuthentication = TSAuthentication()

private var controller: TSAuthenticationController?
Expand Down Expand Up @@ -333,14 +342,22 @@ final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol,
/// • `.success(TSPinCodeRegistrationResult)` on success, or
/// • `.failure(TSAuthenticationError)` on error.
public func registerPinCode(username: String, pinCode: String, completion: @escaping TSPinCodeRegistrationCompletion) {
Task { @MainActor in
let completionBox = UncheckedCompletionBox(completion)

Task { [completionBox] in
do {
let result = try await registerPinCode(username: username, pinCode: pinCode)
completion(.success(result))
Task { @MainActor in
completionBox.call(.success(result))
}
} catch let error as TSPinCodeError {
completion(.failure(.pinCodeError(error)))
Task { @MainActor in
completionBox.call(.failure(.pinCodeError(error)))
}
} catch {
completion(.failure(.pinCodeError(.internal(error))))
Task { @MainActor in
completionBox.call(.failure(.pinCodeError(.internal(error))))
}
}
}
}
Expand Down Expand Up @@ -376,18 +393,49 @@ final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol,
/// • `.success(TSPinCodeAuthenticationResult)` on success, or
/// • `.failure(TSAuthenticationError)` on error.
public func authenticatePinCode(username: String, pinCode: String, challenge: String, completion: @escaping TSPinCodeAuthenticationCompletion) {
Task { @MainActor in

let completionBox = UncheckedCompletionBox(completion)

Task { [completionBox] in
do {
let result = try await authenticatePinCode(username: username, pinCode: pinCode, challenge: challenge)
completion(.success(result))
Task { @MainActor in
completionBox.call(.success(result))
}
} catch let error as TSPinCodeError {
completion(.failure(.pinCodeError(error)))
Task { @MainActor in
completionBox.call(.failure(.pinCodeError(error)))
}
} catch {
completion(.failure(.pinCodeError(.internal(error))))
Task { @MainActor in
completionBox.call(.failure(.pinCodeError(.internal(error))))
}
}
}
}


/// Async variant that actually performs the PIN authentication.
///
/// - Parameters:
/// - username: The user’s identifier.
/// - pinCode: The entered PIN string.
/// - challenge: The server‐provided challenge to prove possession of the PIN key.
/// - Returns: `TSPinCodeAuthenticationResult` on success.
/// - Throws: `TSAuthenticationError` from the controller.
public func authenticatePinCode(username: String, pinCode: String, challenge: String) async throws -> TSPinCodeAuthenticationResult {
guard let controller else { throw TSAuthenticationError.notInitialized }
do {
return try await controller.authenticatePinCode(username: username, pinCode: pinCode, challenge: challenge)
} catch let error as TSPinCodeError {
TSLog.e("PIN code authentication failed with error: \(error)")
throw TSAuthenticationError.pinCodeError(error)
} catch {
TSLog.e("PIN code authentication failed with error: \(error)")
throw TSAuthenticationError.pinCodeError(.internal(error))
}
}

/// Unregister user's Pin Code authenticator.
///
/// - Parameters:
Expand All @@ -396,14 +444,22 @@ final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol,
/// • `.success(TSPinCodeUnregistrationResult)` on success, or
/// • `.failure(TSAuthenticationError)` on error.
public func unregisterPinCode(username: String, completion: @escaping TSPinCodeUnregistrationCompletion) {
Task { @MainActor in
let completionBox = UncheckedCompletionBox(completion)

Task { [completionBox] in
do {
let result = try await unregisterPinCode(username: username)
completion(.success(result))
Task { @MainActor in
completionBox.call(.success(result))
}
} catch let error as TSPinCodeError {
completion(.failure(.pinCodeError(error)))
Task { @MainActor in
completionBox.call(.failure(.pinCodeError(error)))
}
} catch {
completion(.failure(.pinCodeError(.internal(error))))
Task { @MainActor in
completionBox.call(.failure(.pinCodeError(.internal(error))))
}
}
}
}
Expand All @@ -427,27 +483,6 @@ final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol,
throw TSAuthenticationError.pinCodeError(.internal(error))
}
}

/// Async variant that actually performs the PIN authentication.
///
/// - Parameters:
/// - username: The user’s identifier.
/// - pinCode: The entered PIN string.
/// - challenge: The server‐provided challenge to prove possession of the PIN key.
/// - Returns: `TSPinCodeAuthenticationResult` on success.
/// - Throws: `TSAuthenticationError` from the controller.
public func authenticatePinCode(username: String, pinCode: String, challenge: String) async throws -> TSPinCodeAuthenticationResult {
guard let controller else { throw TSAuthenticationError.notInitialized }
do {
return try await controller.authenticatePinCode(username: username, pinCode: pinCode, challenge: challenge)
} catch let error as TSPinCodeError {
TSLog.e("PIN code authentication failed with error: \(error)")
throw TSAuthenticationError.pinCodeError(error)
} catch {
TSLog.e("PIN code authentication failed with error: \(error)")
throw TSAuthenticationError.pinCodeError(.internal(error))
}
}

/**
Retrieves device-specific information, such as public key and its associated ID, which are unique to the application installed on the device.
Expand Down Expand Up @@ -484,6 +519,32 @@ final public class TSAuthentication: NSObject, TSBaseAuthenticationSdkProtocol,
public static func isNativeBiometricsEnrolled() -> Bool {
TSAuthenticationController.isNativeBiometricsEnrolled()
}

/**
Returns the biometric type supported by this device.

The result reflects the hardware capability regardless of enrollment state.
Call ``nativeBiometricsStatus()`` to determine whether the user has actually enrolled.
@return
A `TSBiometricType` value: `.faceID`, `.touchID`, `.opticID`, or `.none`.
*/
public static func nativeBiometricsType() -> TSBiometricType {
TSAuthenticationController.nativeBiometricsType()
}

/**
Returns the current enrollment and availability status of biometric authentication.

Possible values:
- `.available` — biometrics are enrolled and ready to use.
- `.notEnrolled` — hardware is present but the user has not set up biometrics.
- `.notAvailable` — no biometric hardware on this device.
- `.permissionDenied` — hardware exists but the app's biometric access was revoked in Settings.
- `.lockedOut` — too many failed attempts; passcode is required to re-enable biometrics.
*/
public static func nativeBiometricsStatus() -> TSBiometricStatus {
TSAuthenticationController.nativeBiometricsStatus()
}
}


Expand All @@ -505,7 +566,7 @@ private extension TSAuthentication {
public extension TSAuthentication {

/// Options for WebAuthn authentication.
struct WebAuthnAuthenticationOptions: OptionSet {
struct WebAuthnAuthenticationOptions: OptionSet, @unchecked Sendable {
public let rawValue: Int

public init(rawValue: Int) {
Expand Down
Binary file not shown.
Loading