Does AsWebAuthenticationsession support universal links?
Asked Answered
A

3

19

I use AsWebAuthenticationsession to authenticate from another application to my application. I open AsWebAuthenticationsession, and it redirects my application's universal links. The problem is when it redirects my application universal link, it asks to open the App Store. When it redirects I want to close the session. But AsWebAuthenticationsession only takes a custom URL Scheme. How can I handle it securely (because custom URL Schemes are not secure: RFC8252 7.1)

Amuse answered 12/5, 2020 at 9:46 Comment(5)
This Apple forum thread may help but it's still unclear :( developer.apple.com/forums/thread/658334Thromboplastic
Workaround Solution : I passed callbackURLScheme empty string and I handled universal link with userActivity and after that canceled ASWebAuthenticationSession. I staticky defined ASWebAuthenticationSession.Virulence
That's a really good question. I could get it work as @Amuse suggested. But as always SFAuthenticationSession, for pre iOS 12 devices, doesn't seem to work that way ...Fillmore
@Amuse Can you please share the answer with some more details, if you get time? This seems case doesn't seem to have much documentation, and since you have figured out a way to do that, it'd be good to get to know the details. Thank you so much!Spotless
@Amuse Unfortunately, this option does not work for me. Perhaps there are some nuances in this option. At the same time, the universal links themselves have been configured and working for a long time.Nob
P
5

I can confirm this works as of iOS 14 or later, haven't tested on earlier versions though.

When you initialize your ASWebAuthenticationSession you can pass in callbackURLScheme: "https".

When the authentication provider redirects to your universal link, your app delegate's application(_:continue:restorationHandler:) will fire with the correct redirect url, however the ASWebAuthenticationSession's completion handler does not fire and therefore the authentication dialog remains on the screen.

You will need to save a reference to the ASWebAuthenticationSession and cancel() it manually to dismiss it instead.

Pearce answered 18/2, 2022 at 22:39 Comment(1)
Unfortunately, this option does not work for me. I tried to transmit "https", an empty string, nil, the entire redirect url. None of the options work. At the same time, if authorization is performed through an external Safari browser, then the redirect back to the application is successfully performed.Nob
D
0

You can try with this method

To add a singleton class to handle this callback

SceneDelegate.swift

@available(iOS 13.0, *)

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {

    // handle here

    OAuthManager.instance.callBackUserActivity(userActivity: userActivity)

}

OAuthManager.swift

import Foundation

import AuthenticationServices



protocol UserActivityListener {

func callBackUserActivity( userActivity : NSUserActivity )

}



class OAuthManager {

public static let instance = OAuthManager()

var asWebSession: ASWebAuthenticationSession?

}

extension OAuthManager : UserActivityListener {

func callBackUserActivity(userActivity: NSUserActivity) {

    // Get URL components from the incoming user activity.

    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,

          let incomingURL = userActivity.webpageURL,

          let components = NSURLComponents(url: incomingURL,    resolvingAgainstBaseURL: true) else {

        return

    }

    

    // Check for specific URL components that you need.

    guard let path = components.path,

          let params = components.queryItems else {

        return

    }
    // cancel your ASWebAuthenticationSession
    asWebSession?.cancel()


    print("path = \(userActivity.webpageURL)")



    if let token = params.first(where: { $0.name == "token" })?.value {

        print("token = \(token)")

    }

  }


 }

YourViewController.swift

class YourViewController: UIViewController {
// set your instance
var oauthManager = OAuthManager.instance


private func startSignInAsWebAuthSession() {
    let callbackURLScheme = "YOURAPP"
    guard let authURL = URL(string: "YOUR URL LINK") else { return }
        
        self.oauthManager.asWebSession = ASWebAuthenticationSession.init(url: authURL, callbackURLScheme: callbackURLScheme,completionHandler: { callbackURL, error in
            // we dont listen to the call back, this web authentication session only open for login only
        })
        
        oauthManager.asWebSession?.prefersEphemeralWebBrowserSession = true
        oauthManager.asWebSession?.presentationContextProvider = self
        oauthManager.asWebSession?.start()
}
}

extension YourViewController:    ASWebAuthenticationPresentationContextProviding {
   func presentationAnchor(for session: ASWebAuthenticationSession) ->     ASPresentationAnchor {
       ASPresentationAnchor()
    }
  }
Doncaster answered 6/9, 2022 at 2:26 Comment(0)
L
0

As today (2024) the only way I made it work (specially with SwiftUI) was creating a lambda serverless service on AWS, I registered the redirect URL with a path auth\appLogin that handle the response from the OAuth 2.0 in my case the response type was code so I needed to call another API to get the accesss_token then respond with a redirect as URL Scheme registered on my app:

           resolve({
                statusCode: 302,
                headers: {
                    'Location': `myapp://callback?access_token=${JSON.parse(body).access_token}`
                }
            });

And this is my SwiftUI code

       if let authURL = URL(string: "\(baseURL)?response_type=\(responseType)&client_id=\(clientId)&redirect_uri=\(redirectUrl)&scope=\(scopesString)") {
           let scheme = "myapp" // Your app's custom URL scheme
           let session = ASWebAuthenticationSession(url: authURL, callbackURLScheme: scheme) { callbackURL, error in
               guard error == nil, let callbackURL = callbackURL else {
                   print("Authorization failed: \(String(describing: error))")
                   return
               }
               
               // Handle the authorization code from the callbackURL
               let queryItems = URLComponents(string: callbackURL.absoluteString)?.queryItems
               if let access_token = queryItems?.first(where: { $0.name == "access_token" })?.value {
                   print("Authorization token: \(access_token)")
               }
           }
           
           session.presentationContextProvider = contextProvider
           session.start()
       }

Also remember to register your URL Scheme :

urlschememyapp

Lissa answered 2/3 at 16:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.