Swift login alert shows up when you logout

Can you also share screen by screen (the whole flow) how it behaves? The reason I’m asking it is that with previous developers asking we weren’t able to get enough info to troubleshoot that, hence having as much additional info as possible is very helpful!

talexis@sharpsoftwaredev.onmicrosoft.com

First we are calling login using below code,

    let scope = "openid profile offline_access email ssp:post"
    let audience = "https://device-messaging-apis”

    AuthManager.shared.patchMode = false
    Auth0
        .webAuth()
        .scope(scope)  
        .audience(audience)
        .start {
            switch $0 {
            case .failure(let error):
                print("Error: \(error)")
            case .success(let credentials):
                if(!AuthManager.shared.store(credentials: credentials)) {
                    print("Failed to store credentials")
                } else {
                    self.handleSuccessLogin()
                }
            }
    }

After execute this code we will get login like below screen shot

For logout,

After pressing Logout below code we are executing,
We are calling below code when pressing logout option,
Auth0.webAuth().clearSession(federated: true) { (isLoggedOut) in
DispatchQueue.main.async {
let keychain = A0SimpleKeychain(service: “Auth0”)
keychain.clearAll()
//Perform UI Updates
self.credentials = nil
_ = self.credentialsManager.clear()
callback(isLoggedOut)
}
}

After this we are getting default alert like below screen shot, (This alert is showing both login and logout)

Thank you a lot! Let me investigate it and get back to you once I have news to share!

Any news? Same error here

Any news yet? Having the same issue

Hi folks,

I’ve started looking into this. I was able to reproduce it using our quickstart, but I don’t fully understand the cause yet, or how to fix it. I’ll be digging deeper over the next week or two so look for an update here soon.

Thanks,

Matt

Hi folks,

Long post following.

I think it’s important to note that clearSession clears the Auth0 session and optionally the IdP session from your system browser. You can simply remove access tokens and/or refresh tokens within your app to “deauthorize” the app itself. However, note that existing SSO sessions could allow the user to “log in” to the app again without entering username/password, which may be confusing to the user and/or not what you want to happen.

Let’s dig into this some more:

The SDK currently uses (assuming iOS13) ASWebAuthenticationSession to open a web browser for the user. This has the following properties:

  • The iOS native "AppName" wants to use "tenant" to sign in prompt will appear when you want to use shared cookies in Safari. This is a hard requirement of Apple’s implementation and can’t be changed. The current behavior of the Auth0 Swift SDK is to use shared cookies, but this optional within ASWebAuthenticationSession and we discuss a way around it later.
  • Since we’re using shared cookies, Safari will have access to any existing SSO sessions (that is, if the user had an existing Facebook session and chose Facebook sign-in they would not be prompted for Facebook username/password)
  • Reference: Apple Developer Documentation

As far as experiencing the “wants to sign in with…” native prompt when calling clear session, we’re stuck with it due to the cookie behavior we’re using in the SDK. However, here are some things to consider:

  • We can minimize the login/logout calls to the browser by storing a refresh token locally (Auth0.swift: Save and Renew Tokens)
  • We can revoke the refresh token instead of “logging out”—this could confuse users when they try to “log in” again because they may have an SSO session stored in the system browser and may not have to enter username/password. Reference: GitHub - auth0/Auth0.swift: Auth0 SDK for Apple platforms
    • You can work around this with short Auth0 sessions (like a 5 minute session…by the time the user tries to sign in again the session will be long expired)
    • you can force force new “log in” attempts to require username/password by storing the logout time in the keychain when revoking the token, and using this to calculate an appropriate max_age to send to the /authorize endpoint to require reauthentication (e.g. max_age = date.current - date.last_logout - 10000 …10000 being some appropriate clock skew fudge factor).

Another solution involves forking the Auth0 Swift SDK or rolling your own logic. The iOS ASWebAuthentication method can be called with prefersEphemeralWebBrowserSession set to True. This opens a Safari instance that does not use shared cookies and users will not see the “wants to sign in with…” native prompt. However, the browser session will not have access to any SSO sessions. If you don’t need or care about SSO this may be a good option for you. It’s possible in the future we could add a configuration option in the Auth0 Swift SDK that would force it not to use shared cookies (please post here if this a feature you would use).

12 Likes

Thanks for this huge write-up Matt!

1 Like

@matt.macadam Thank you for the detailed explanation! Would you mind clarifying a few things?

Firstly:

  • I DO need to support SSO on iOS with Refresh Tokens.
  • I DO need to silently log out a user without requiring user confirmation of Apple’s dialog about shared cookies. (Basically, security – if Refresh Token is revoked, I cannot allow the user to acquire a new Refresh Token without requiring user to re-enter username/password.)

To solve this, you provided two options:

  1. Short Auth0 sessions – How do I configure that?
  2. Passing a calculated “max_age” to /authorize – How do I do that? I know how to edit the source code, but I don’t understand if you mean the Cache-Control: max-age=<seconds> header or some non-standard header, or a custom property in the post-body, or something else.

Lastly, do I need to implement BOTH options for this to work, or just one?

Thank you!!!

1 Like

@Ethan-VisualVocal you can adjust your SSO session lifetime in your tenant settings, under the Advanced tab.

You said “I DO need to support SSO on iOS with Refresh Tokens.” Can you elaborate on what you expect a user interaction to look like for this?

As far as the two options I mentioned, you would implement one or the other…I think technically you could do both but there’s no benefit. If you didn’t want to set your global session timeouts to be short then you would use the second option.

max_age is an OIDC parameter that:

Specifies the allowable elapsed time in seconds since the last time the End-User was actively authenticated by the OP. If the elapsed time is greater than this value, the OP MUST attempt to actively re-authenticate the End-User. (The max_age request parameter corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] max_auth_age request parameter.) When max_age is used, the ID Token returned MUST include an auth_time Claim Value. (Final: OpenID Connect Core 1.0 incorporating errata set 1)

So it’s added as a parameter on the call to /authorize. I think to send it in Auth0.swift you would add it like this on the login method:

Auth0
.authentication()
.login(
    usernameOrEmail: "support@auth0.com",
    password: "secret-password",
    realm: "Username-Password-Authentication",
    scope: "openid",
    parameters: [max_age: "4900"])

With the caveat that I’m not an iOS developer and that might make your phone catch on fire. The idea here is:

  1. You record the time the user logged out of the app (or rather, the time they clicked “log out” and you revoked the refresh token)
  2. User tries to sign in again–you do some date math and determine it has been 5000 seconds since the token was revoked.
  3. You send a request to /authorize with max_age=4900
  4. Authorization server receives the request and sees that the user last logged in well over 4900 seconds ago (remember you revoked the token 5000 seconds ago so they logged in sometime before that)
  5. Authorization server requires the user to enter username/password again.

It’s important to note you’re doing this for user experience, not security. There’s nothing to stop the user or a proxy from tampering with the max_age parameter and reusing the SSO session. That is probably fine for this use case, but if you wanted to confirm the parameter was sent properly you would check the auth_time claim returned in the id_token and make sure it contains a sensible value.

Update: I should note this only applies to auth0 database connections. If you are redirecting to an upstream IdP (like Facebook), auth0 can guarantee that some sort of exchange with the upstream IdP took place, but we can’t guarantee the exchange involved a username and password (for example, the user may have had an existing session). So for an upstream IdP you can’t trust the auth_time claim to prove that the user provided a username and password.

4 Likes

Thanks a lot for sharing this knowledge Matt!

We are facing the issue, when we logout from Auth0.
its showing Login alert ( and asking :- “wants to sign in…” ), not showing logout thing.

Can you provide some guidance to overcome this issue.

1 Like

Outside of a Native login flow, is there any way to avoid the “…wants to sign in” iOS prompt for logout? I am receiving this issue in React Native, running on iOS.

3 Likes

Same question as @dylan4, I’m getting a prompt for both authorize and logout. Running on React Native. Saw another thread related to this App would like to use Auth0 to Sign In prompt displays on Logout (React Native) but it seems dead.

1 Like

I have the same problem. When I call authorize or clearSession I get a pop-up stating "App" Wants to Use "auth0.com" to Sign In - This allows the app and website to share information about you..

The ugly thing is that when the user presses "Logout" in the App, the pop-up talks about "Sign In".

1 Like

I feel this thread is dead as well. I ended up deciding to implement my own login because the UX problem caused by this issue is unacceptable.

This really should be a high priority for you guys. It is completely broken to show users a “wants to sign in” when they are trying to logout. That is completely not what they are trying to do yet they see a message to the contrary.

I’ve never seen this with Google or other logins, when I have used their SSO directly.

Also, for our users, the first login will give them an error telling them to go check their email for a change password link. However, the Auth0 code, even though it gave an error and there is no refreshToken or credential, will assume that the user is logged in, and on subsequent attempts to login, it will continue to assume that the same user is logging in and won’t give the user a chance to enter a userid and password. The authentication tries the same old password. At that point, a user is locked out. Even deleting the app won’t fix the issue. I had to go in and add code to logoutUserWithCallback to the failed login attempt. Now the user sees a second “auth0.com wants to sign-in message”, for a failing transaction.

Logout and error handling of a login, is a fundamental part of an authentication mechanism. I can’t believe that this is not at the top of your lists for something to fix.

8 Likes

I agree with @mahboud; I’m really hoping this is one of your highest priorities at the moment. This makes for a terrible user experience. Being an authentication service you should have this covered; I don’t feel like we should have to jump through hoops and use roundabout code in order to get basic login/logout functionality to work as it should. ESPECIALLY when you clearly state that doing so would mean giving up on some other important functionality, like SSO. I would really appreciate an update on this issue; it looks like the last time an Auth0 employee commented here was January. It’s August.

1 Like

Hi. Checking to see if there are any updates?

Hi folks,

I was asked to provide an update here. The situation is mostly unchanged, but it is a little easier to work around this now if you’re using our Swift SDK.

First, a reminder that the “(app) wants to use (website) to sign in” construct is enforced by iOS when you redirect to a “regular” Safari browser for a user to log in to your app. That redirect is usually executed by calling ASWebAuthenticationSession (this is what our SDK does for ios 13+) and the default behavior for that method is to open a “regular” Safari browser.

When I say a “regular” Safari browser I mean the same instance you would find yourself in if you opened it from the home screen–with all your cookies and session data. Apple enforces this requirement as kind of a warning that some personal information will be available to the site if you continue (I covered this in more detail in previous posts). The advantage of this is if the user has existing SSO sessions for Google/Facebook, etc. they don’t have to enter a username and password again.

I agree it doesn’t make a lot of sense that iOS raises the same prompt for logging in and logging out–in my opinion there should be another parameter you can pass to ASWebAuthenticationSession (maybe isLoggingOut: true ) to get it to display a message with the appropriate context. Hopefully one of these days.

There are two ways to avoid the bad logout UX:

  • Don’t use the browser to log out (solution detailed in previous posts)
  • Call ASWebAuthenticationSession with prefersEphemeralWebBrowserSession:True

I have mentioned the second option before, but it used to require forking our SDK to implement. As of May 2020 we have an option in the SDK to use ephemeral sessions and avoid the iOS popup:

https://github.com/auth0/Auth0.swift/blob/master/FAQ.md#1-how-can-i-disable-the-login-alert-box

That is probably the easiest way to handle the problem today. It disables the popup for logging in and logging out. Note also that if you use an ephemeral session to log in there is no need to redirect to the web browser for logout–since you used an ephemeral session there is no web browser session to terminate.

Final note: It looks like our Xamarin SDK will also be getting ephemeral sessions soon:

https://github.com/auth0/auth0-oidc-client-net/pull/173

Thanks,

2 Likes