Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mac catalyst can not open login window #401

Open
rushairer opened this issue Nov 17, 2022 · 1 comment
Open

mac catalyst can not open login window #401

rushairer opened this issue Nov 17, 2022 · 1 comment

Comments

@rushairer
Copy link
Contributor

OAuth 5.3.2/ SwiftUI/ using macOS 13 run catalyst mode, will get this error:

2022-11-17 15:42:03.532115+0800 Crossword[1778:4730281] [TraitCollection] Class _UIFindNavigatorViewController overrides the -traitCollection getter, which is not supported. If you're trying to override traits, you must use the appropriate API.
2022-11-17 15:42:20.836892+0800 Crossword[1778:4730281] [AXRuntimeCommon] Unknown client: Crossword
[Debug] OAuth2: Starting authorization
[Debug] OAuth2: No access token, checking if a refresh token is available
[Debug] OAuth2: Error refreshing token: I don't have a refresh token, not trying to refresh
[Debug] OAuth2: Opening authorize URL embedded:  *****************HIDDEN*****************
[Debug] OAuth2: The operation couldn’t be completed. (com.apple.AuthenticationServices.WebAuthenticationSession error 2.)
Authorization was canceled or went wrong: The operation couldn’t be completed. (com.apple.AuthenticationServices.WebAuthenticationSession error 2.).

Both iOS/Mac are OK, only catalyst can not work :(

import OAuth2
#if os(iOS)
import UIKit
#elseif os(macOS)
import AppKit
#endif
import Combine
import WebKit

public struct OAuth2Configuration {
    public init(clientId: String, authorizeUri: String, tokenUri: String, redirectUris: [String], scope: String, customParameters: OAuth2StringDict) {
        self.clientId = clientId
        self.authorizeUri = authorizeUri
        self.tokenUri = tokenUri
        self.redirectUris = redirectUris
        self.scope = scope
        self.customParameters = customParameters
    }
    
    let clientId: String
    let authorizeUri: String
    let tokenUri: String
    let redirectUris: [String]
    let scope: String
    let customParameters: OAuth2StringDict
    let logLevel: OAuth2LogLevel = .debug
}

public class OAuth2Coordinator: ObservableObject {
    // MARK: Stored Properties
    
    @Published var accessToken: String?
    
    public private(set) var text = "Hello, World!"
    
    private var oauth2: OAuth2?
    private var cancellables = Set<AnyCancellable>()
    
    
    // MARK: Initialization
    public init(configuration: OAuth2Configuration) {
        let oauth2 = OAuth2CodeGrant(settings: [
            "client_id": configuration.clientId,
            "client_secret": "",
            "authorize_uri": configuration.authorizeUri,
            "token_uri": configuration.tokenUri,
            "redirect_uris": configuration.redirectUris,
            "scope": configuration.scope,
            "parameters": configuration.customParameters,
            "secret_in_body": false,
            "keychain": true,
            "use_pkce": true,
        ] as OAuth2JSON)
        oauth2.logger = OAuth2DebugLogger(configuration.logLevel)
        oauth2.afterAuthorizeOrFail = { [unowned self] authParameters, error in
            self.accessToken = oauth2.accessToken
        }
        self.oauth2 = oauth2
    }
    
    // MARK: Methods
    public func checkToken() {
        if let hasUnexpiredAccessToken = self.oauth2?.hasUnexpiredAccessToken(), hasUnexpiredAccessToken {
            self.oauth2?.doRefreshToken(callback: { [unowned self] authParameters, error in
                self.accessToken = self.oauth2?.accessToken
            })
        }
    }
    
    public func setupWhenUIIsReady() {
        if let oauth2 = self.oauth2 {
#if os(iOS)
            let rootViewController = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first?.rootViewController
#elseif os(macOS)
            let rootViewController = NSApplication.shared.windows.first?.windowController
#endif
            
            if rootViewController != nil {
                oauth2.authConfig.authorizeEmbedded = true
                oauth2.authConfig.authorizeContext = rootViewController
                oauth2.authConfig.ui.useSafariView = false
                oauth2.authConfig.ui.useAuthenticationSession = true
                oauth2.authConfig.ui.prefersEphemeralWebBrowserSession = true
            }
        }
    }
    
    public func authorize() {
        if let oauth2 = self.oauth2 {
            oauth2.authorize() { authParameters, error in
                if let error = error {
                    print("Authorization was canceled or went wrong: \(error).")
                }
            }
        }
    }
    
    public func unauthorize() {
        signOutTokenFromServer()
        removeCookies()
        self.oauth2?.abortAuthorization()
        self.oauth2?.forgetTokens()
    }
    
    private func signOutTokenFromServer() {
        if let oauth2 = self.oauth2 {
            if let signOutUriString = oauth2.clientConfig.customParameters?.first(where: { $0.key == "signOutUri" })?.value {
                var req = oauth2.request(forURL: URL(string: signOutUriString)!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
                req.httpMethod = "POST"
                let task = oauth2.session.dataTask(with: req) { data, response, error in
                    if let response = response as? HTTPURLResponse, response.statusCode == 204 {
                        print("Sign out from server.")
                    } else if let error = error {
                        print(error)
                    }
                }
                task.resume()
            }
        }
    }
    
    private func removeCookies() {
        HTTPCookieStorage.shared.removeCookies(since: Date.distantPast)
        print("All cookies deleted.")
        
        WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
            records.forEach { record in
                WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {})
                print("Cookie \(record) deleted.")
            }
        }
    }
}
@rushairer
Copy link
Contributor Author

in completionHandler got this error:

Printing description of error:
▿ Optional<Error>
  - some : Error Domain=com.apple.AuthenticationServices.WebAuthenticationSession Code=2 "Cannot start ASWebAuthenticationSession without providing presentation context. Set presentationContextProvider before calling -start." UserInfo={NSDebugDescription=Cannot start ASWebAuthenticationSession without providing presentation context. Set presentationContextProvider before calling -start.}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant