Skip to content

Commit

Permalink
Add prefersEphemeralSession parameter for external user-agents (openi…
Browse files Browse the repository at this point in the history
…d#645)

* Add emphemeral browser option iOS/Catalyst user agents.

Adds BOOL properties to iOS/Catalyst-related methods which allow setting the ASWebAuthenticationSession property prefersEphemeralWebBrowserSession.

* Add emphemeral browser option to macOS user agent.

Adds BOOL arguments to macOS-related methods which allow setting the ASWebAuthenticationSession property prefersEphemeralWebBrowserSession.

* Update doc comments based on review feedback.

Also fixes some formatting and code symbol annotation to support Xcode Quick Help.

* Replace 'Catalyst' with 'external' in method brief
  • Loading branch information
danblakemore authored Aug 19, 2022
1 parent a447315 commit c1a5080
Show file tree
Hide file tree
Showing 14 changed files with 222 additions and 12 deletions.
27 changes: 24 additions & 3 deletions Source/AppAuth/iOS/OIDAuthState+IOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
and update the OIDAuthState with the results (@c
OIDAuthState.updateWithTokenResponse:error:).
@param authorizationRequest The authorization request to present.
@param presentingViewController The view controller from which to present the
@c SFSafariViewController. On iOS 13, the window of this UIViewController
is used as the ASPresentationAnchor.
@param presentingViewController The view controller to use for presenting the authentication UI.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
Expand All @@ -50,6 +48,29 @@ NS_ASSUME_NONNULL_BEGIN
presentingViewController:(UIViewController *)presentingViewController
callback:(OIDAuthStateAuthorizationCallback)callback;

/*! @brief Convenience method to create a @c OIDAuthState by presenting an authorization request
(optionally using an emphemeral browser session that shares no cookies or data with the
normal browser session) and performing the authorization code exchange in the case of code
flow requests. For the hybrid flow, the caller should validate the id_token and c_hash, then
perform the token request (@c OIDAuthorizationService.performTokenRequest:callback:)
and update the OIDAuthState with the results (@c
OIDAuthState.updateWithTokenResponse:error:).
@param authorizationRequest The authorization request to present.
@param presentingViewController The view controller to use for presenting the authentication UI.
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
*/
+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
presentingViewController:(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthStateAuthorizationCallback)callback
API_AVAILABLE(ios(13));

+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
callback:(OIDAuthStateAuthorizationCallback)callback API_AVAILABLE(ios(11)) API_UNAVAILABLE(macCatalyst)
Expand Down
20 changes: 20 additions & 0 deletions Source/AppAuth/iOS/OIDAuthState+IOS.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,26 @@ @implementation OIDAuthState (IOS)
callback:callback];
}

+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
presentingViewController:(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthStateAuthorizationCallback)callback {
id<OIDExternalUserAgent> externalUserAgent;
#if TARGET_OS_MACCATALYST
externalUserAgent = [[OIDExternalUserAgentCatalyst alloc]
initWithPresentingViewController:presentingViewController
prefersEphemeralSession:prefersEphemeralSession];
#else // TARGET_OS_MACCATALYST
externalUserAgent = [[OIDExternalUserAgentIOS alloc]
initWithPresentingViewController:presentingViewController
prefersEphemeralSession:prefersEphemeralSession];
#endif // TARGET_OS_MACCATALYST
return [self authStateByPresentingAuthorizationRequest:authorizationRequest
externalUserAgent:externalUserAgent
callback:callback];
}

#if !TARGET_OS_MACCATALYST
+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
Expand Down
23 changes: 20 additions & 3 deletions Source/AppAuth/iOS/OIDAuthorizationService+IOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface OIDAuthorizationService (IOS)

/*! @brief Perform an authorization flow using \SFSafariViewController.
/*! @brief Perform an authorization flow, presenting an appropriate browser for the user to
authenticate.
@param request The authorization request.
@param presentingViewController The view controller from which to present the
\SFSafariViewController.
@param presentingViewController The view controller from which to present authentication UI.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
Expand All @@ -43,6 +43,23 @@ NS_ASSUME_NONNULL_BEGIN
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
presentingViewController:(UIViewController *)presentingViewController
callback:(OIDAuthorizationCallback)callback;

/*! @brief Perform an authorization flow using the @c ASWebAuthenticationSession optionally using an
emphemeral browser session that shares no cookies or data with the normal browser session.
@param request The authorization request.
@param presentingViewController The view controller from which to present authentication UI.
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
*/
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
presentingViewController:(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthorizationCallback)callback API_AVAILABLE(ios(13));

@end

NS_ASSUME_NONNULL_END
Expand Down
16 changes: 16 additions & 0 deletions Source/AppAuth/iOS/OIDAuthorizationService+IOS.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ @implementation OIDAuthorizationService (IOS)
return [self presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:callback];
}

+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
presentingViewController:(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthorizationCallback)callback {
id<OIDExternalUserAgent> externalUserAgent;
#if TARGET_OS_MACCATALYST
externalUserAgent = [[OIDExternalUserAgentCatalyst alloc]
initWithPresentingViewController:presentingViewController
prefersEphemeralSession:prefersEphemeralSession];
#else // TARGET_OS_MACCATALYST
externalUserAgent = [[OIDExternalUserAgentIOS alloc] initWithPresentingViewController:presentingViewController
prefersEphemeralSession:prefersEphemeralSession];
#endif // TARGET_OS_MACCATALYST
return [self presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:callback];
}

@end

NS_ASSUME_NONNULL_END
Expand Down
9 changes: 9 additions & 0 deletions Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ API_AVAILABLE(macCatalyst(13)) API_UNAVAILABLE(ios)
(UIViewController *)presentingViewController
NS_DESIGNATED_INITIALIZER;

/*! @brief Create an external user-agent which optionally uses a private authentication session.
@param presentingViewController The view controller from which to present the browser.
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
*/
- (nullable instancetype)initWithPresentingViewController:
(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession;

@end

NS_ASSUME_NONNULL_END
Expand Down
12 changes: 12 additions & 0 deletions Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ @interface OIDExternalUserAgentCatalyst ()<ASWebAuthenticationPresentationContex

@implementation OIDExternalUserAgentCatalyst {
UIViewController *_presentingViewController;
BOOL _prefersEphemeralSession;

BOOL _externalUserAgentFlowInProgress;
__weak id<OIDExternalUserAgentSession> _session;
Expand All @@ -53,6 +54,16 @@ - (nullable instancetype)initWithPresentingViewController:
return self;
}

- (nullable instancetype)initWithPresentingViewController:
(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession {
self = [self initWithPresentingViewController:presentingViewController];
if (self) {
_prefersEphemeralSession = prefersEphemeralSession;
}
return self;
}

- (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
session:(id<OIDExternalUserAgentSession>)session {
if (_externalUserAgentFlowInProgress) {
Expand Down Expand Up @@ -89,6 +100,7 @@ - (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
}];

authenticationVC.presentationContextProvider = self;
authenticationVC.prefersEphemeralWebBrowserSession = _prefersEphemeralSession;
_webAuthenticationVC = authenticationVC;
openedUserAgent = [authenticationVC start];

Expand Down
20 changes: 18 additions & 2 deletions Source/AppAuth/iOS/OIDExternalUserAgentIOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,29 @@ API_UNAVAILABLE(macCatalyst)
"initWithPresentingViewController:presentingViewController");

/*! @brief The designated initializer.
@param presentingViewController The view controller from which to present the
\SFSafariViewController.
@param presentingViewController The view controller from which to present the authentication UI.
@discussion The specific authentication UI used depends on the iOS version and accessibility
options. iOS 8 uses the system browser, iOS 9-10 use @c SFSafariViewController, iOS 11 uses
@c SFAuthenticationSession
(unless Guided Access is on which does not work) or uses @c SFSafariViewController, and iOS
12+ uses @c ASWebAuthenticationSession (unless Guided Access is on).
*/
- (nullable instancetype)initWithPresentingViewController:
(UIViewController *)presentingViewController
NS_DESIGNATED_INITIALIZER;

/*! @brief Create an external user-agent which optionally uses a private authentication session.
@param presentingViewController The view controller from which to present the browser.
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
@discussion Authentication is performed with @c ASWebAuthenticationSession (unless Guided Access
is on), setting the ephemerality based on the argument.
*/
- (nullable instancetype)initWithPresentingViewController:
(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession
API_AVAILABLE(ios(13));

@end

NS_ASSUME_NONNULL_END
Expand Down
14 changes: 13 additions & 1 deletion Source/AppAuth/iOS/OIDExternalUserAgentIOS.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ @interface OIDExternalUserAgentIOS ()<SFSafariViewControllerDelegate>

@implementation OIDExternalUserAgentIOS {
UIViewController *_presentingViewController;
BOOL _prefersEphemeralSession;

BOOL _externalUserAgentFlowInProgress;
__weak id<OIDExternalUserAgentSession> _session;
Expand Down Expand Up @@ -75,6 +76,16 @@ - (nullable instancetype)initWithPresentingViewController:
return self;
}

- (nullable instancetype)initWithPresentingViewController:
(UIViewController *)presentingViewController
prefersEphemeralSession:(BOOL)prefersEphemeralSession {
self = [self initWithPresentingViewController:presentingViewController];
if (self) {
_prefersEphemeralSession = prefersEphemeralSession;
}
return self;
}

- (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
session:(id<OIDExternalUserAgentSession>)session {
if (_externalUserAgentFlowInProgress) {
Expand Down Expand Up @@ -115,7 +126,8 @@ - (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
}];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
if (@available(iOS 13.0, *)) {
authenticationVC.presentationContextProvider = self;
authenticationVC.presentationContextProvider = self;
authenticationVC.prefersEphemeralWebBrowserSession = _prefersEphemeralSession;
}
#endif
_webAuthenticationVC = authenticationVC;
Expand Down
26 changes: 25 additions & 1 deletion Source/AppAuth/macOS/OIDAuthState+Mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,37 @@ NS_ASSUME_NONNULL_BEGIN
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
@discussion This method adopts ASWebAuthenticationSession for macOS 10.15 and above or the default browser otherwise.
@discussion This method adopts @c ASWebAuthenticationSession for macOS 10.15 and above or the
default browser otherwise.
*/
+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
presentingWindow:(NSWindow *)presentingWindow
callback:(OIDAuthStateAuthorizationCallback)callback;

/*! @brief Convenience method to create a @c OIDAuthState by presenting an authorization request
(optionally using an emphemeral browser session that shares no cookies or data with the
normal browser session) and performing the authorization code exchange in the case of code
flow requests. For the hybrid flow, the caller should validate the id_token and c_hash, then
perform the token request (@c OIDAuthorizationService.performTokenRequest:callback:)
and update the OIDAuthState with the results using
@c OIDAuthState.updateWithTokenResponse:error:.
@param authorizationRequest The authorization request to present.
@param presentingWindow The window to present the @c ASWebAuthenticationSession UI.
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
*/
+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
presentingWindow:(NSWindow *)presentingWindow
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthStateAuthorizationCallback)callback
API_AVAILABLE(macos(10.15));

/*! @param authorizationRequest The authorization request to present.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
Expand Down
12 changes: 12 additions & 0 deletions Source/AppAuth/macOS/OIDAuthState+Mac.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ @implementation OIDAuthState (Mac)
externalUserAgent:externalUserAgent
callback:callback];
}
+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
presentingWindow:(NSWindow *)presentingWindow
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthStateAuthorizationCallback)callback {
OIDExternalUserAgentMac *externalUserAgent =
[[OIDExternalUserAgentMac alloc] initWithPresentingWindow:presentingWindow
prefersEphemeralSession:prefersEphemeralSession];
return [self authStateByPresentingAuthorizationRequest:authorizationRequest
externalUserAgent:externalUserAgent
callback:callback];
}

+ (id<OIDExternalUserAgentSession>)
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
Expand Down
20 changes: 19 additions & 1 deletion Source/AppAuth/macOS/OIDAuthorizationService+Mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,30 @@ NS_ASSUME_NONNULL_BEGIN
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
@discussion This method adopts ASWebAuthenticationSession for macOS 10.15 and above or the default browser otherwise.
@discussion This method adopts @c ASWebAuthenticationSession for macOS 10.15 and above or the
default browser otherwise.
*/
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
presentingWindow:(NSWindow *)presentingWindow
callback:(OIDAuthorizationCallback)callback;

/*! @brief Perform an authorization flow using the @c ASWebAuthenticationSession optionally using an
emphemeral browser session that shares no cookies or data with the normal browser session.
@param request The authorization request.
@param presentingWindow The window to present the authentication flow.
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
*/
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
presentingWindow:(NSWindow *)presentingWindow
prefersEphemeralSession:(BOOL)prefersEphemeralSession
callback:(OIDAuthorizationCallback)callback
API_AVAILABLE(macos(10.15));

/*! @brief Perform an authorization flow using the default browser.
@param request The authorization request.
@param callback The method called when the request has completed or failed.
Expand Down
Loading

0 comments on commit c1a5080

Please sign in to comment.