How to keep browser from showing sign in screen on every launch?
Hello, I'm using AppAuth on macOS (11.2.3) in a native Swift application and it works in terms of logging into Google and using the APIs. However, every time I launch the app, it asks me to re-authenticate in the browser (in this case Safari, but I have tried it with Chrome as well), even if I just used it minutes ago. I'm using it only with a single Google account on a single machine.
Is there a way I should be using a stored refresh token on the next launch to tell AppAuth to bypass the browser authentication and just use the saved token (if it's still valid)? I can save it in NSUserDefaults and/or iCloud Keychain but I don't know how to tell AppAuth about it.
Code that I call when app launches:
func authorizeGoogleAccount() -> Bool {
let dg = DispatchGroup()
dg.enter()
let serverPort: UInt16 = 62626
let issuer = URL(string: "https://accounts.google.com")!
// discovers endpoints
OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration, error in
guard let config = configuration else {
print("Error retrieving discovery document: \(error?.localizedDescription ?? "Unknown error")")
return
}
let kSuccessUrlString = "http://openid.github.io/AppAuth-iOS/redirect/"
let url = URL(string: kSuccessUrlString)
// Starts a loopback HTTP redirect listener to receive the code. This needs to be started first,
// as the exact redirect URI (including port) must be passed in the authorization request.
self.redirectHandler = OIDRedirectHTTPHandler(successURL: url)
let errPtr = NSErrorPointer(nilLiteral: ())
guard let redirectUri = self.redirectHandler?.startHTTPListener(errPtr, withPort: serverPort) else {
print("Failed to start HTTP auth listener.")
return
}
// Configure the auth request.
let request = OIDAuthorizationRequest(configuration: config, clientId: kGoogleClientID, clientSecret: kGoogleClientSecret, scopes: [kGoogleDriveAuthScope, kGoogleMailAuthScope], redirectURL: redirectUri, responseType: OIDResponseTypeCode, additionalParameters: nil)
// Perform the auth request.
self.redirectHandler?.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request) { authState, error in
NSRunningApplication.current.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
if let noptAuthState = authState, let token = noptAuthState.lastTokenResponse?.accessToken {
self.googleAuthState = noptAuthState
self.googleAuthAccessToken = token
print("Google auth access token = \(token)")
if let refreshToken = noptAuthState.lastTokenResponse?.refreshToken {
self.googleAuthRefreshToken = refreshToken
print("Google auth refresh token = \(refreshToken)")
kKeychain.set(refreshToken, forKey: kGoogleKeychainItemName, withAccess: .accessibleAfterFirstUnlockThisDeviceOnly)
} else {
print("No refresh token returned.")
_ = self.freshGoogleAccessToken()
}
} else {
print("Auth error = \(error?.localizedDescription ?? "<nil>")")
}
dg.leave()
}
}
dg.wait()
return self.googleAuthAccessToken != nil
}
As per the OpenID standard, adding this query param: ‘?prompt=login’ to the URL should present the login screen every single time irrespective of the session's availability.