From 647723186e9e944f77a6dd72c7ef4f2fa6ac5c47 Mon Sep 17 00:00:00 2001 From: Varun Santhanam Date: Sun, 20 Aug 2023 07:32:27 -0700 Subject: [PATCH] Document WebAuthentication --- Sources/SafariUI/SafariUI.docc/SafariUI.md | 2 +- Sources/SafariUI/SafariUI.docc/SafariView.md | 2 +- .../SafariUI.docc/WebAuthentication.md | 17 ++++++++ Sources/WebAuthentication/Modifiers.swift | 6 +++ Sources/WebAuthentication/Presentation.swift | 24 +++++++++++ .../WebAuthentication/WebAuthentication.swift | 42 +++++++++++++++++++ 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 Sources/SafariUI/SafariUI.docc/WebAuthentication.md diff --git a/Sources/SafariUI/SafariUI.docc/SafariUI.md b/Sources/SafariUI/SafariUI.docc/SafariUI.md index b8d46586c..9c47de484 100644 --- a/Sources/SafariUI/SafariUI.docc/SafariUI.md +++ b/Sources/SafariUI/SafariUI.docc/SafariUI.md @@ -4,7 +4,7 @@ SafariServices in SwiftUI ## Overview -`SafariUI` is a package that wraps [`SafariServices`](https://developer.apple.com/documentation/safariservices/) for use with SwiftUI applications. Currently, it contains a single SwiftUI view, called `SafariView`, which wraps [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller). +`SafariUI` is a package that allows you to display instances of Safari inside your SwiftUI applications. Use ``WebAuthentication`` when using Safari to authenticate users, and ``SafariView`` for a standard Safari experience. ## Topics diff --git a/Sources/SafariUI/SafariUI.docc/SafariView.md b/Sources/SafariUI/SafariUI.docc/SafariView.md index b7c09acdb..56a5d81b7 100644 --- a/Sources/SafariUI/SafariUI.docc/SafariView.md +++ b/Sources/SafariUI/SafariUI.docc/SafariView.md @@ -6,7 +6,7 @@ ## Overview -The view includes Safari features such as Reader, AutoFill, Fraudulent Website Detection, and content blocking. The user's activity and interaction with `SafariView` are not visible to your app, which cannot access AutoFill data, browsing history, or website data. You do not need to secure data between your app and Safari. If you would like to share data between your app and Safari, so it is easier for a user to log in only one time, use [`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) instead. +The view includes Safari features such as Reader, AutoFill, Fraudulent Website Detection, and content blocking. The user's activity and interaction with `SafariView` are not visible to your app, which cannot access AutoFill data, browsing history, or website data. You do not need to secure data between your app and Safari. If you would like to share data between your app and Safari, so it is easier for a user to log in only one time, use ``WebAuthentication`` instead. - Important: In accordance with [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/), this view must be used to visibly present information to users; the view may not be hidden or obscured by other views or layers. Additionally, an app may not use `SafariView` to track users without their knowledge and consent. diff --git a/Sources/SafariUI/SafariUI.docc/WebAuthentication.md b/Sources/SafariUI/SafariUI.docc/WebAuthentication.md new file mode 100644 index 000000000..93ac06790 --- /dev/null +++ b/Sources/SafariUI/SafariUI.docc/WebAuthentication.md @@ -0,0 +1,17 @@ +# ``WebAuthentication`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) +} + +## Overview + +Use a `WebAuthentication` instance to authenticate a user through a web service, including one run by a third party. Initialize the session with a URL that points to the authentication webpage. When the user starts the authentication session, the operating system shows a modal view telling them which domain the app is authenticating with and asking whether to proceed. If the user proceeds with the authentication attempt, a browser loads and displays the page, from which the user can authenticate. In iOS, the browser is a secure, embedded web view. In macOS, the system opens the user’s default browser if it supports web authentication sessions, or Safari otherwise. + +On completion, the service sends a callback URL to the session with an authentication token. The session passes this URL back to the app through a completion handler. `AuthenticationSession` ensures that only the calling app’s session receives the authentication callback, even when more than one app registers the same callback URL scheme. + +`WebAuthentication` is not a normal SwiftUI view. Unlike ``SafariView``, **must** be presented using one of the following included view modifiers: + +- ``SwiftUI/View/webAuthentication(_:webAuthentication:)-74m38`` +- ``SwiftUI/View/webAuthentication(_:webAuthentication:)-5x82p`` +- ``SwiftUI/View/webAuthentication(_:id:webAuthentication:)`` diff --git a/Sources/WebAuthentication/Modifiers.swift b/Sources/WebAuthentication/Modifiers.swift index 6a9e3290a..9d9edfcef 100644 --- a/Sources/WebAuthentication/Modifiers.swift +++ b/Sources/WebAuthentication/Modifiers.swift @@ -27,6 +27,12 @@ import SwiftUI public extension View { + /// Set the private authentication requirements for authentication sessions within this view. + /// + /// This modifier is the equivelent of the of the [`prefersEphemeralWebBrowserSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3237231-prefersephemeralwebbrowsersessio) property of a [`ASWebAuthnticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) + /// + /// - Parameter prefersEphemeralWebBrowserSession: Whether or not the web authentication session should ask for a private authentication session. + /// - Returns: The modified view func webAuthenticationPrefersEphemeralWebBrowserSession(_ prefersEphemeralWebBrowserSession: Bool = true) -> some View { let modifer = WebAuthenticationPrefersEphemeralWebBrowserSessionModifier(prefersEphemeralWebBrowserSession: prefersEphemeralWebBrowserSession) return ModifiedContent(content: self, modifier: modifer) diff --git a/Sources/WebAuthentication/Presentation.swift b/Sources/WebAuthentication/Presentation.swift index ca43bb61c..237e23de7 100644 --- a/Sources/WebAuthentication/Presentation.swift +++ b/Sources/WebAuthentication/Presentation.swift @@ -27,6 +27,14 @@ import SwiftUI public extension View { + /// Presents a ``WebAuthentication`` when a binding to a Boolean value that you provide is `true`. + /// + /// Use this method when you want to present a ``WebAuthentication`` to the user when a Boolean value you provide is true. + /// + /// - Parameters: + /// - isPresented: A binding to a Boolean value that determines whether to present the ``WebAuthentication`` that you create in the modifier’s content closure. + /// - webAuthentication: A closure that returns the ``WebAuthentication`` to present + /// - Returns: The modified view func webAuthentication( _ isPresented: Binding, webAuthentication: @escaping () -> WebAuthentication @@ -35,6 +43,14 @@ public extension View { return ModifiedContent(content: self, modifier: modifier) } + /// Presents a ``WebAuthentication`` using the given item as a data source for the ``WebAuthentication``'s content + /// + /// Use this method when you need to present a ``WebAuthentication`` with content from a custom data source. + /// + /// - Parameters: + /// - item: A binding to an optional source of truth for the ``WebAuthentication``. When item is non-nil, the system passes the item’s content to the modifier’s closure. You display this content in a ``WebAuthentication`` that you create that the system displays to the user. If item changes, the system dismisses the ``WebAuthentication`` and replaces it with a new one using the same process. + /// - webAuthentication: A closure that returns the ``WebAuthentication`` to present + /// - Returns: The modified view func webAuthentication( _ item: Binding, webAuthentication: @escaping (Item) -> WebAuthentication @@ -43,6 +59,14 @@ public extension View { return ModifiedContent(content: self, modifier: modifier) } + /// Presents a ``WebAuthentication`` using the given item as a data source for the ``WebAuthentication``'s content + /// + /// Use this method when you need to present a ``WebAuthentication`` with content from a custom data source. + /// + /// - Parameters: + /// - item: A binding to an optional source of truth for the ``WebAuthentication``. When item is non-nil, the system passes the item’s content to the modifier’s closure. You display this content in a ``WebAuthentication`` that you create that the system displays to the user. If item changes, the system dismisses the ``WebAuthentication`` and replaces it with a new one using the same process. + /// - id: A keypath used to generate stable identifier for instances of `Item`. + /// - webAuthentication: A closure that returns the ``WebAuthentication`` to present. func webAuthentication( _ item: Binding, id: KeyPath, diff --git a/Sources/WebAuthentication/WebAuthentication.swift b/Sources/WebAuthentication/WebAuthentication.swift index a4327f00c..bdc2f7445 100644 --- a/Sources/WebAuthentication/WebAuthentication.swift +++ b/Sources/WebAuthentication/WebAuthentication.swift @@ -32,6 +32,47 @@ public struct WebAuthentication { // MARK: - Initializers /// Create a web authentication session + /// + /// You must present a `WebAuthentication` challenge to your users using one of our provided presentation view modifiers: + /// + /// - ``SwiftUI/View/webAuthentication(_:webAuthentication:)-74m38`` + /// - ``SwiftUI/View/webAuthentication(_:webAuthentication:)-5x82p`` + /// - ``SwiftUI/View/webAuthentication(_:id:webAuthentication:)`` + /// + /// For example: + /// + /// ```swift + /// struct AuthenticateButton: View { + /// var body: some View { + /// + /// @State + /// var isPresented = false + /// + /// static let authURL = URL(string: "https://www.myserver.com/auth?argument=foo")! + /// static let scheme = "myserver" + /// + /// Button("Connect Github") { + /// isPresented.toggle() + /// } + /// .webAuthentication($isPresented) { + /// WebAuthentication( + /// url: authURL, + /// callbackURLScheme: scheme + /// ) { result in + /// do { + /// let callback = try result.get() + /// // Authentication complete. Perform callback. + /// } catch { + /// // Authentication failed. Display error message to user. + /// } + /// } + /// } + /// } + /// } + /// ``` + /// + /// You cannot display a `WebAuthentication` cannot be displayed any other way. + /// /// - Parameters: /// - url: The URL pointing to the authentication page /// - callbackURLScheme: The URL scheme that the app should expect when receiving the authentication callback @@ -48,6 +89,7 @@ public struct WebAuthentication { // MARK: - API + /// A completion handler for the web authentication session. public typealias CompletionHandler = (Result) -> Void // MARK: - Private