16

My app has a "Sign in with the Apple" account feature. I am wondering if there is sign out feature from the Apple account.

I tried the below but doesn't get success

    let request = ASAuthorizationAppleIDProvider().createRequest()

    request.requestedOperation = .operationLogout

    let authorizationController = ASAuthorizationController(authorizationRequests: [request])

    authorizationController.performRequests()
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Dipendra Dubey
  • 187
  • 1
  • 1
  • 8

2 Answers2

12

Apple only allows currently for the user to perform a signout (iOS/watchOS/tvOS) or shown as a revoke of permissions to us. They recommend you get the state of the credentials before use to check for revoke and if that has occurred to delete any local information (Remove the user identifier where ever you have it stored) (And possibly change UI if needed; For example like showing login view).

        let appleIDProvider = ASAuthorizationAppleIDProvider()
    appleIDProvider.getCredentialState(forUserID: KeychainItem.currentUserIdentifier) { (credentialState, error) in
        switch credentialState {
        case .authorized:
            // The Apple ID credential is valid.
            break
        case .revoked:
            // The Apple ID credential is revoked.
            break
        case .notFound:
            // No credential was found, so show the sign-in UI.
            break
        default:
            break
        }
    }

You could provide a prompt to the user on signout guiding them to revoke in their device's settings as well and listen for the change notification.

Tal Cohen
  • 1,308
  • 10
  • 20
SierraMike
  • 1,539
  • 1
  • 11
  • 18
  • 6
    the code above is just to check the current status, can you please suggest to log the user out as asked in the question. – Mohit G. Mar 12 '20 at 10:14
  • 3
    @MohitG. As stated before; Apple does not have a sign out function available to use for the "Sign in with Apple". Currently, the user must go into the Settings application and revoke permission. If the revoked status is detected by an application; Clear any local OAuth or other authentication data stored locally and require reauthentication. You could also clear your local stored token to your server and then regardless of the "Sign in with Apple" status require reauthentication. – SierraMike Mar 14 '20 at 15:15
  • this is confusing me as well, so in mobile apps, if I sign in with Apple and essentially want to 'logout' of my app, is it nothing more than redirecting back to the sign-in page (apart from the logic that I need to perform for the logout process for my own app)? – Reza Apr 04 '20 at 15:38
  • @Reza As of right now this is correct. When you logout of an application that uses Sign in with Apple they are only removing their local tokens to access their server and showing you the login page again (Even if you are still technically signed in with Apple via in Settings). – SierraMike Apr 05 '20 at 04:52
  • I guess I should have clarified. I am trying to figure out apart from my own apps logout process code (delete securely stored items from the phone etc) I don’t necessarily need to do anything specific to Apple sign in per se? – Reza Apr 05 '20 at 06:01
  • No @Reza. Nothing else is needed! – SierraMike Apr 05 '20 at 06:25
  • 5
    If they're not going to do this then they need to provide name/email credentials when user tries to re-authorize. There's a pretty common edge case where user deletes account and business doesn't archive user data after account deletion. The app either has to tell user to revoke permission or setup custom flow to collect email and name which defeats most of the purpose of this feature. – Braden Holt Jun 15 '20 at 19:14
  • @BradenHolt Very true. Now that I have finished implementing Apple ID I'm in the same boat as you guys. The solution is inadequate. There is no way to programatically sign out the user. Now from 30th June 2022 we have to provide a way for the user to delete the whole account on the remote server. That means if the user wants to sign back in afterwards, it's not even possible, because name and email won't be provided from Apple, unless the user stops using Apple ID by navigating to the Settings first. It couldn't be more complicated. What was Apple thinking? – Houman Jun 26 '22 at 14:07
  • @Houman doesn't keeping email and name in the keychain solve this problem? When a user deletes the account, you don't have to clear the keychain. – Wojciech Kulik Aug 09 '22 at 06:09
  • @WojciechKulik That's a good workaround actually. It's not quite as privacy clean as I hoped to. But since it's locally stored, it should be ok. Thanks for sharing. – Houman Aug 09 '22 at 07:21
1

You need to delete the existing item from the keychain.

This is my sample code, using Apple sample code.
You can get sample code from Apple

Apple recommend you get the state of the credentials before use to check for revoke and if that has occurred to delete any local information

struct KeychainItem {

    
    init(service: String, account: String, accessGroup: String? = nil) {
        self.service = service
        self.account = account
        self.accessGroup = accessGroup
    }

    static func deleteUserIdentifierFromKeychain() {
        do { //please change service id to your bundle ID 
            try KeychainItem(service: "com.example.apple-samplecode", account: "userIdentifier").deleteItem()
        } catch {
            print("Unable to delete userIdentifier from keychain")
        }
    }

   func deleteItem() throws {
        // Delete the existing item from the keychain.
        let query = KeychainItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
        let status = SecItemDelete(query as CFDictionary)
        
        // Throw an error if an unexpected status was returned.
        guard status == noErr || status == errSecItemNotFound else { throw KeychainError.unhandledError }
    }

keychainQuery

keychainQuery is from apple sample code.

    
    private static func keychainQuery(withService service: String, account: String? = nil, accessGroup: String? = nil) -> [String: AnyObject] {
        var query = [String: AnyObject]()
        query[kSecClass as String] = kSecClassGenericPassword
        query[kSecAttrService as String] = service as AnyObject?
        
        if let account = account {
            query[kSecAttrAccount as String] = account as AnyObject?
        }
        
        if let accessGroup = accessGroup {
            query[kSecAttrAccessGroup as String] = accessGroup as AnyObject?
        }
        
        return query
    }
Hideyasu.T
  • 809
  • 6
  • 5
  • it gives me following errors 1. Type 'KeychainItem' has no member 'keychainQuery' 2. Cannot find 'KeychainError' in scope Let me know how to resolve this two errors – Vibhuti.patel Oct 05 '21 at 13:12
  • I add keychainQuery. – Hideyasu.T Nov 04 '21 at 12:29
  • 2
    This isn't a solution - you've misunderstood Apple's sample code, which just uses the keychain to manually store the user identifier. Deleting such a keycahin item (which won't exist unless you put it there) won't change the authentication status. – Adrian Jul 07 '22 at 04:34
  • I have an application that uses apple sign in. And i know that if the user sign in for the first time in the application we can get the name, and eamil of the user and an auth id. since i dont update the application since last 2 years so there are more then 1 million user who has sign in (more then 1 time) to application that results in creating duplicate accounts, with name and email are null. now is there any way that i remove all those users form the apple sign . – Engr.Aftab Ufaq Aug 01 '23 at 09:48