Dev environment: MacbookPro, Ventura 13.0.1 XCode 14.1
I’m implementing a feature for an existing MacOS application, which will allow users to launch zoom meetings from the application, and am trying to use ASWebAuthenticationSession to implement OAuth2. I’ve confirmed that universal links are correctly configured and working for the app (which is using an https-based redirect URI).
In my app delegate, I’ve implemented the following for universal links:
- (BOOL)application:(NSApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler
{
if ([userActivity.activityType isEqualToString: NSUserActivityTypeBrowsingWeb]) {
NSURL *url = userActivity.webpageURL;
if ([url.path containsString:[NSString stringWithStdString:Zoom::kFragment]])
{
std::string urlStr((url.absoluteString).stdString); //DBG
DialogFactory::GetInstance()->Message("Universal links handler - AppDelegate: Handling response: " + urlStr); //DBG
return YES;
}
}
return NO;
}
And here’s the code for the extension which conforms to ASWebAuthenticationPresentationContextProviding:
@objc extension ViewController : ASWebAuthenticationPresentationContextProviding {
@objc public func userLogin(){
guard let oauthMgr : ZoomOAuthMgr = self.oauthDelegate else {
return
}
guard let authURL = oauthMgr.getAuthURL() else {
return
}
guard let scheme = oauthMgr.getScheme() else {
return
}
let session = ASWebAuthenticationSession(url: authURL, callbackURLScheme: scheme) { callbackURL, error in
/* TODO: guard */
self.handleOAuthResponse(callbackUrl: callbackURL, err: error)
}
session.presentationContextProvider = self
session.prefersEphemeralWebBrowserSession = true
session.start()
}
func handleOAuthResponse(callbackUrl: URL?, err: Error?) {
guard callbackUrl != nil else {return}
guard err == nil else {
/* TODO: err handling */
return
}
guard let url : URLComponents = URLComponents(string: callbackUrl!.absoluteString) else {return}
guard let authCode = url.queryItems?.first(where: { $0.name == "code" })?.value else {return}
/* TODO: request access token */
}
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return self.view.window ?? ASPresentationAnchor()
}
}
I've confirmed that the scheme passed to ASWebAuthenticationSession doesn't contain any special characters and matches the redirect URL scheme (https).
Expected behaviour: Starting a new session should launch the user’s default browser and present a login page. After the user is authenticated, the auth server’s response should be redirected to the app, where the session handler passed to ASWebAuthenticationSession will handle the response.
Actual behaviour:
When Chrome is the default browser, starting a session launches a Chrome window, which closes immediately. So no login page is presented. My session handler receives a copy of authURL
that was sent to Chrome. No error is received by the handler or indicated in XCode. No crash logs are generated. System logs don’t seem to offer any clues. And I see no evidence of network traffic suggesting the auth request was ever sent to the auth server.
When Safari is the default browser, starting a session launches Safari with the login page. After logging in, instead of redirecting back to the application and invoking my session handler, a 404 page is displayed. Also displayed is a banner near the top of the window, containing an button with instructions: “Open in the MyApp app”. Clicking the button redirects back to the app, and the response, which should populate callbackURL
is instead received by the universal links handler (AppDelegate::application:continueUserActivity:restorationHandler:). My session handler never receives the response or an error. And no error is generated in XCode either.
When Firefox is the default browser, Safari is launched instead, and the same behaviour described above is seen.
Possible clue:
I’ve tried encoding authURL
before handing it to ASWebAuthenticationSession, using various character sets, with no success. But if I encode the authURL
using the URLHostAllowedCharacterSet: [nsUrlStr stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]
- Chrome doesn't crash. Instead it displays a popup with the message “Your connection to this site is not secure”.
I’d really appreciate any help getting this working as expected. Or any suggested alternatives to get OAuth working with https-based redirects for a MacOS app.
Thanks!