kishikawakatsumi / KeychainAccess

Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS.
MIT License
7.89k stars 785 forks source link

Keychain value sometimes returning nil in background even with .afterFirstUnlock accessibility #342

Closed Daltron closed 6 years ago

Daltron commented 6 years ago

Why I use the keychain manager

To store an access token for each request that is made within the application. If the request is unauthorized, then the user is logged out of the app and required to sign back in.

Background

For the past several months, the app I have been working on has been going through a state where some users are getting randomly getting logged out while in the background because the requests they are making are sometimes unauthorized because I believe the access token in the keychain is not available at the particular time they need it. It's nearly impossible to reproduce as it happens anywhere between 1-24 hours after the app is opened.

How I use KeychainAccess

override init() {
     keychain = Keychain(service: Bundle.main.identifier).accessibility(.afterFirstUnlock)
     super.init()
}
 func saveAccessToken(_ token: String) {
     do {
          try keychain.set(token, key: accessTokenKey)
     } catch let error {
          Logger.logFailure("Failed to save access token to keychain: \(error)")
     }
}
var accessToken: String? {
     do {
          let token = try keychain.get(accessTokenKey)
          return token
     } catch {
            Logger.logFailure("Failed to retrieve access token from keychain: \(error)")
        }
        return nil
}

I have the .afterFirstUnlock accessibility in my service, but yet the keychain appears locked at certain times. I can 100% confirm that all devices that are experiencing the issue have met the "first unlock" requirement. Is there something I'm not doing right with KeychainAccess?

It may also be worth mentioning that I just recently converted from this library: Locksmith. Could there be any possibility that the accessibility settings from here could be clashing/overriding KeychainAccess's accessibility settings?

Any help would be GREATLY GREATLY appreciated! 😄

Daltron commented 6 years ago

I'm happy to report back that changing the service name when initializing an instance of Keychain fixed the issue. It looks like somehow a previous keychain's accessibility settings created with the Locksmith pod were overriding all settings no matter what.

RamblinWreck77 commented 6 years ago

@Daltron Interesting, this could be the cause of what I'm seeing. Even accessible always isn't working in production.

Were you able to upgrade/fix-it in place or did you have to remove the entire keychain and start over?

Daltron commented 6 years ago

@RamblinWreck77 This happened such a long time ago but if I remember correctly, I had to explicitly change the service name of the keychain and start from scratch. That may not be ideal for your scenario but it worked out ok for mine.

RamblinWreck77 commented 6 years ago

@Daltron Interesting, my library doesn't have a "service name" parameter. I'll have to dig into how this one works and see what it's really setting.

RamblinWreck77 commented 6 years ago

@Daltron Do you have any thoughts about having two Keychains (assuming I use KeychainAccess and set different serviceIDs), one .whenUnlocked for secure stuff and .always for stuff that doesn't need to be secure?

I was wondering if you tried something similar.

Daltron commented 6 years ago

@RamblinWreck77 I would still use just one keychain. There is no harm is storing stuff as secure even when it doesn't need to be.