Skip to content

Add support for enrolling passkeys with My Account API [SDK-5543] #962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
May 29, 2025

Conversation

Widcket
Copy link
Contributor

@Widcket Widcket commented May 23, 2025

  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

📋 Changes

This PR adds:

  • A new API client for the My Account API, including its own error type MyAccountError.
  • A sub-client for the authentication methods endpoints.
    • A method for requesting a passkey enrollment challenge.
    • A method for enrolling a newly created passkey.

The new API client was built in a more self-contained fashion, to make it easier to extract into its own package in the future. This required a bit of refactoring of the existing code.

🎯 Testing

Besides a full test suite, the changes were tested manually with Xcode 16.3 (16E140), using:

  • Simulator running iOS 18.4
  • iPhone 14 Pro Max running iOS 18.4

Sorry, something went wrong.

@Widcket Widcket requested a review from a team as a code owner May 23, 2025 19:16
}

/// Generic representation of Auth0 API errors.
public protocol Auth0APIError: Auth0Error {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into its own file.

@@ -27,15 +27,9 @@ public struct AuthenticationError: Auth0APIError, @unchecked Sendable {
/// HTTP status code of the response.
public let statusCode: Int

/// The underlying `Error` value, if any. Defaults to `nil`.
public var cause: Error? {
Copy link
Contributor Author

@Widcket Widcket May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into Auth0APIError.

/// - [callIsActive](https://developer.apple.com/documentation/foundation/urlerror/2293147-callisactive)
///
/// The underlying `URLError` is available in the ``Auth0Error/cause-9wuyi`` property.
public var isNetworkError: Bool {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into Auth0APIError, so it's available for all API error types, not just AuthenticationError.

@@ -1,77 +0,0 @@
import Foundation
Copy link
Contributor Author

@Widcket Widcket May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The contents of this file were moved to AuthenticationHandlers.swift. Since the internal Response type now makes use of Swift 6's typed throws, most handlers no longer need that last catch: callback(.failure(AuthenticationError(cause: error))).

callback(.success(dictionary))
} else {
callback(.failure(ManagementError(from: response)))
}
} catch let error as ManagementError {
Copy link
Contributor Author

@Widcket Widcket May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the internal Response type now makes use of Swift 6's typed throws, these handlers no longer need that last catch: callback(.failure(ManagementError(cause: error))).

@@ -23,14 +23,9 @@ public struct ManagementError: Auth0APIError, @unchecked Sendable {
/// HTTP status code of the response.
public let statusCode: Int

/// The underlying `Error` value, if any. Defaults to `nil`.
public var cause: Error? {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into Auth0APIError.


@testable import Auth0

extension SecKey {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into Generators.swift.

Widcket added 3 commits May 23, 2025 20:32
…h0/Auth0.swift into feature/myaccount-passkey-enrollment
// MARK: - Passkey Enrollment

#if PASSKEYS_PLATFORM
@available(iOS 16.6, macOS 13.5, visionOS 1.0, *)
Copy link
Contributor Author

@Widcket Widcket May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the implementation of the method that requests a passkey enrollment challenge.

telemetry: self.telemetry)
}

@available(iOS 16.6, macOS 13.5, visionOS 1.0, *)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the implementation of the method that enrolls the new passkey.

struct Response<E: Auth0APIError> {
let data: Data?
let response: HTTPURLResponse?
let error: Error?

func result() throws -> Any? {
func result() throws(E) -> JSONResponse? {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This internal method is now using a typed throw.


@available(iOS 16.6, macOS 13.5, visionOS 1.0, *)
extension ASAuthorizationPlatformPublicKeyCredentialRegistration: SignupPasskey {}

@available(iOS 16.6, macOS 13.5, visionOS 1.0, *)
extension ASAuthorizationPublicKeyCredentialAttachment {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into NewPasskey.swift, so it can be used by both the Authentication API client and the My Account API client.

}

#if PASSKEYS_PLATFORM
if #available(iOS 16.6, macOS 13.5, visionOS 1.0, *) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the tests for:

  • The method for requesting an enrollment challenge
  • The method for enrolling a newly created passkey


@testable import Auth0

class MyAccountErrorSpec: QuickSpec {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the tests for the new error type MyAccountError.

Widcket added 10 commits May 23, 2025 20:54
///
/// ```swift
/// Auth0
/// .myAccount(token: apiCredentials.accessToken)
Copy link
Contributor

@pmathew92 pmathew92 May 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't .myAccount(token:) return a new instance of MyAccount each time we invoke these api's ?
With the following enroll api ,now we will have two separate instances of MyAccount calling these individual apis. This might cause state management issue when these classes evolve in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's deliberate, and in line with the existing clients in the SDK, for instance the Authentication API client, the Management API client (for users endpoints), and the Web Auth client.

Similarly, every time you call Auth0.myAccount().authenticationMethods you get a new instance of the authentication methods sub client.

Like with the existing clients, you can always store an instance in a constant or variable if needed.

///
/// ```swift
/// Auth0
/// .myAccount(token: apiCredentials.accessToken)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same query as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered in #962 (comment)

Copy link
Contributor

@pmathew92 pmathew92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM , just a minor query

@Widcket Widcket merged commit e120d73 into master May 29, 2025
12 of 13 checks passed
@Widcket Widcket deleted the feature/myaccount-passkey-enrollment branch May 29, 2025 22:13
@Widcket Widcket mentioned this pull request May 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants