openid / AppAuth-iOS

iOS and macOS SDK for communicating with OAuth 2.0 and OpenID Connect providers.
https://openid.github.io/AppAuth-iOS
Apache License 2.0
1.78k stars 776 forks source link

Proper usage of SFSafariViewController vs. SFAuthenticationSession to open a URL after logging in #187

Closed mattio closed 6 years ago

mattio commented 6 years ago

I was reading through issue #120 and had a question about how to properly use SFAuthenticationSession. The scenario is that I have successfully logged in using SSO and now I want to open a web view to a site also protected by that same SSO solution.

For iOS 9 and 10, SFSafariViewController works as expected. For iOS 11 I've been able to get SFAuthenticationSession working after cobbling together some examples, but I'm not sure I'm using it correctly. I've reviewed the Apple docs, looked on Stack Overflow, and Googled around quite a bit.

If I've already logged in and I'm just trying to open up the URL of site protected by SSO, is this how it could be done with SFAuthenticationSession?

 - (IBAction)runSsoTest:(id)sender {
    NSURL *destinationUrl = [NSURL URLWithString:@"https://www.example.com/secure"];

    if (@available(iOS 11.0, *)) {
        self.session = [[SFAuthenticationSession alloc]
                                            initWithURL:destinationUrl
                                            callbackURLScheme:@"com.example.demo"
                                            completionHandler:^(NSURL * _Nullable callbackURL, NSError * _Nullable error) {
                                                // TODO: Nothing to do here?
        }];
        BOOL started = [self.session start];
    }
    else {
        // Our app is only iOS 9+, so we can assume SFSafariViewController is present here.
        SFSafariViewController *vc = [[SFSafariViewController alloc] initWithURL:destinationUrl];
        [self presentViewController:vc animated:YES completion:nil];
    }
} 
NitroNbg commented 6 years ago

I'd also like to know the right way to handle opening the URL from the same provider using SFAuthenticationSession. Unfortunately though, the above solution doesn't work for me. The SFAS prompt closes as soon as it opens :(

WilliamDenniss commented 6 years ago

Your code looks fine to me. The thing is that SFAuthenticationSession (I believe) was designed for authentication only. For one, you'll have the authentication permission dialog show every time you open it. Assuming that UX is acceptable, then you can certainly use it. If you wish to do things like have the website close it automatically then you can do it like we do in OAuth. That is, you can pass in a custom URI scheme in callbackURLScheme which if browsed to (e.g. the website redirects the user to it as a result of some action) will close the ViewController. Conversely, if you don't care about that then just pass in something random that should never be browsed to (like com.example.yourapp.donotuse).

As for the completion handler, this is optional and really up to you. It's a useful entry point if you need some actions to trigger when the user closes the ViewController (either via the UI button, or via browsing to a link using the callbackURLScheme).

As no doubt you saw, this is how we do it in AppAuth itself: https://github.com/openid/AppAuth-iOS/blob/96ea3e3dc691d76d814015ce7c47a6c1ccaf8d10/Source/iOS/OIDAuthorizationUICoordinatorIOS.m#L91-L110

WilliamDenniss commented 6 years ago

@NitroNbg regarding the prompt closing immediately: are you retaining the SFAuthenticationSession object? For example by assigning it as a property of an object that is referenced by another object?

If the view controller disappears after it is shown (i.e. after the user interacts with the permission dialog), that could happen if the website redirected to the callbackURLScheme immediately.