diff --git a/ios/A0Auth0.m b/ios/A0Auth0.m index 8de671a6..599ee4c5 100644 --- a/ios/A0Auth0.m +++ b/ios/A0Auth0.m @@ -2,6 +2,9 @@ #import "A0Auth0.h" #import +#if __has_include("AuthenticationServices/AuthenticationServices.h") +#import +#endif #import #if __has_include("RCTUtils.h") @@ -10,8 +13,12 @@ #import #endif +#define ERROR_CANCELLED @{@"error": @"a0.session.user_cancelled",@"error_description": @"User cancelled the Auth"} +#define ERROR_FAILED_TO_LOAD @{@"error": @"a0.session.failed_load",@"error_description": @"Failed to load url"} + @interface A0Auth0 () @property (weak, nonatomic) SFSafariViewController *last; +@property (strong, nonatomic) NSObject *authenticationSession; @property (copy, nonatomic) RCTResponseSenderBlock sessionCallback; @property (assign, nonatomic) BOOL closeOnLoad; @end @@ -30,9 +37,15 @@ - (dispatch_queue_t)methodQueue } RCT_EXPORT_METHOD(showUrl:(NSString *)urlString closeOnLoad:(BOOL)closeOnLoad callback:(RCTResponseSenderBlock)callback) { - [self presentSafariWithURL:[NSURL URLWithString:urlString]]; - self.closeOnLoad = closeOnLoad; - self.sessionCallback = callback; + if (@available(iOS 11.0, *)) { + self.sessionCallback = callback; + self.closeOnLoad = closeOnLoad; + [self presentAuthenticationSession:[NSURL URLWithString:urlString]]; + } else { + [self presentSafariWithURL:[NSURL URLWithString:urlString]]; + self.sessionCallback = callback; + self.closeOnLoad = closeOnLoad; + } } RCT_EXPORT_METHOD(oauthParameters:(RCTResponseSenderBlock)callback) { @@ -58,17 +71,64 @@ - (void)presentSafariWithURL:(NSURL *)url { self.last = controller; } +- (void)presentAuthenticationSession:(NSURL *)url { + + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url + resolvingAgainstBaseURL:NO]; + NSArray *queryItems = urlComponents.queryItems; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name=%@", @"redirect_uri"]; + NSURLQueryItem *queryItem = [[queryItems + filteredArrayUsingPredicate:predicate] + firstObject]; + NSString *callbackURLScheme = queryItem.value; + RCTResponseSenderBlock callback = self.sessionCallback ? self.sessionCallback : ^void(NSArray *_unused) {}; + + if (@available(iOS 12.0, *)) { + self.authenticationSession = [[ASWebAuthenticationSession alloc] + initWithURL:url callbackURLScheme:callbackURLScheme + completionHandler:^(NSURL * _Nullable callbackURL, + NSError * _Nullable error) { + if ([[error domain] isEqualToString:ASWebAuthenticationSessionErrorDomain] && + [error code] == ASWebAuthenticationSessionErrorCodeCanceledLogin) { + callback(@[ERROR_CANCELLED, [NSNull null]]); + } else if(error) { + callback(@[error, [NSNull null]]); + } else if(callbackURL) { + callback(@[[NSNull null], callbackURL.absoluteString]); + } + self.authenticationSession = nil; + }]; + [(ASWebAuthenticationSession*) self.authenticationSession start]; + } else if (@available(iOS 11.0, *)) { + self.authenticationSession = [[SFAuthenticationSession alloc] + initWithURL:url callbackURLScheme:callbackURLScheme + completionHandler:^(NSURL * _Nullable callbackURL, + NSError * _Nullable error) { + if ([[error domain] isEqualToString:SFAuthenticationErrorDomain] && + [error code] == SFAuthenticationErrorCanceledLogin) { + callback(@[ERROR_CANCELLED, [NSNull null]]); + } else if(error) { + callback(@[error, [NSNull null]]); + } else if(callbackURL) { + callback(@[[NSNull null], callbackURL.absoluteString]); + } + self.authenticationSession = nil; + }]; + [(SFAuthenticationSession*) self.authenticationSession start]; + } +} + - (void)terminateWithError:(id)error dismissing:(BOOL)dismissing animated:(BOOL)animated { RCTResponseSenderBlock callback = self.sessionCallback ? self.sessionCallback : ^void(NSArray *_unused) {}; if (dismissing) { [self.last.presentingViewController dismissViewControllerAnimated:animated completion:^{ if (error) { - callback(@[error]); + callback(@[error, [NSNull null]]); } }]; } else if (error) { - callback(@[error]); + callback(@[error, [NSNull null]]); } self.sessionCallback = nil; self.last = nil; @@ -122,22 +182,14 @@ - (NSDictionary *)generateOAuthParameters { #pragma mark - SFSafariViewControllerDelegate - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { - NSDictionary *error = @{ - @"error": @"a0.session.user_cancelled", - @"error_description": @"User cancelled the Auth" - }; - [self terminateWithError:error dismissing:NO animated:NO]; + [self terminateWithError:ERROR_CANCELLED dismissing:NO animated:NO]; } - (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully { if (self.closeOnLoad && didLoadSuccessfully) { [self terminateWithError:[NSNull null] dismissing:YES animated:YES]; } else if (!didLoadSuccessfully) { - NSDictionary *error = @{ - @"error": @"a0.session.failed_load", - @"error_description": @"Failed to load url" - }; - [self terminateWithError:error dismissing:YES animated:YES]; + [self terminateWithError:ERROR_FAILED_TO_LOAD dismissing:YES animated:YES]; } } diff --git a/webauth/agent.js b/webauth/agent.js index da97f9dd..e852b60b 100644 --- a/webauth/agent.js +++ b/webauth/agent.js @@ -17,11 +17,13 @@ export default class Agent { resolve(event.url); }; Linking.addEventListener('url', urlHandler); - NativeModules.A0Auth0.showUrl(url, closeOnLoad, err => { + NativeModules.A0Auth0.showUrl(url, closeOnLoad, (error, redirectURL) => { Linking.removeEventListener('url', urlHandler); - if (err) { - reject(err); - } else if (closeOnLoad) { + if (error) { + reject(error); + } else if(redirectURL) { + resolve(redirectURL); + } else if(closeOnLoad) { resolve(); } });