Helper functions for saving text in Keychain securely for iOS, OS X, tvOS and watchOS.

Last update: Jun 21, 2022

Helper functions for storing text in Keychain for iOS, macOS, tvOS and WatchOS

Carthage compatible CocoaPods Version Swift Package Manager compatible License Platform

This is a collection of helper functions for saving text and data in the Keychain. As you probably noticed Apple's keychain API is a bit verbose. This library was designed to provide shorter syntax for accomplishing a simple task: reading/writing text values for specified keys:

let keychain = KeychainSwift()
keychain.set("hello world", forKey: "my key")
keychain.get("my key")

The Keychain library includes the following features:

What's Keychain?

Keychain is a secure storage. You can store all kind of sensitive data in it: user passwords, credit card numbers, secret tokens etc. Once stored in Keychain this information is only available to your app, other apps can't see it. Besides that, operating system makes sure this information is kept and processed securely. For example, text stored in Keychain can not be extracted from iPhone backup or from its file system. Apple recommends storing only small amount of data in the Keychain. If you need to secure something big you can encrypt it manually, save to a file and store the key in the Keychain.

Setup

There are four ways you can add KeychainSwift to your project.

Add source (iOS 7+)

Simply add KeychainSwiftDistrib.swift file into your Xcode project.

Setup with Carthage (iOS 8+)

Alternatively, add github "evgenyneu/keychain-swift" ~> 19.0 to your Cartfile and run carthage update.

Setup with CocoaPods (iOS 8+)

If you are using CocoaPods add this text to your Podfile and run pod install.

use_frameworks!
target 'Your target name'
pod 'KeychainSwift', '~> 19.0'

Setup with Swift Package Manager

Legacy Swift versions

Setup a previous version of the library if you use an older version of Swift.

Usage

Add import KeychainSwift to your source code unless you used the file setup method.

String values

let keychain = KeychainSwift()
keychain.set("hello world", forKey: "my key")
keychain.get("my key")

Boolean values

let keychain = KeychainSwift()
keychain.set(true, forKey: "my key")
keychain.getBool("my key")

Data values

let keychain = KeychainSwift()
keychain.set(dataObject, forKey: "my key")
keychain.getData("my key")

Removing keys from Keychain

keychain.delete("my key") // Remove single key
keychain.clear() // Delete everything from app's Keychain. Does not work on macOS.

Return all keys

let keychain = KeychainSwift()
keychain.allKeys // Returns the names of all keys

Advanced options

Keychain item access

Use withAccess parameter to specify the security level of the keychain storage. By default the .accessibleWhenUnlocked option is used. It is one of the most restrictive options and provides good data protection.

let keychain = KeychainSwift()
keychain.set("Hello world", forKey: "key 1", withAccess: .accessibleWhenUnlocked)

You can use .accessibleAfterFirstUnlock if you need your app to access the keychain item while in the background. Note that it is less secure than the .accessibleWhenUnlocked option.

See the list of all available access options.

Synchronizing keychain items with other devices

Set synchronizable property to true to enable keychain items synchronization across user's multiple devices. The synchronization will work for users who have the "Keychain" enabled in the iCloud settings on their devices.

Setting synchronizable property to true will add the item to other devices with the set method and obtain synchronizable items with the get command. Deleting a synchronizable item will remove it from all devices.

Note that you do NOT need to enable iCloud or Keychain Sharing capabilities in your app's target for this feature to work.

// First device
let keychain = KeychainSwift()
keychain.synchronizable = true
keychain.set("hello world", forKey: "my key")

// Second device
let keychain = KeychainSwift()
keychain.synchronizable = true
keychain.get("my key") // Returns "hello world"

We could not get the Keychain synchronization work on macOS.

Sharing keychain items with other apps

In order to share keychain items between apps on the same device they need to have common Keychain Groups registered in Capabilities > Keychain Sharing settings. This tutorial shows how to set it up.

Use accessGroup property to access shared keychain items. In the following example we specify an access group "CS671JRA62.com.myapp.KeychainGroup" that will be used to set, get and delete an item "my key".

let keychain = KeychainSwift()
keychain.accessGroup = "CS671JRA62.com.myapp.KeychainGroup" // Use your own access goup

keychain.set("hello world", forKey: "my key")
keychain.get("my key")
keychain.delete("my key")
keychain.clear()

Note: there is no way of sharing a keychain item between the watchOS 2.0 and its paired device: https://forums.developer.apple.com/thread/5938

Setting key prefix

One can pass a keyPrefix argument when initializing a KeychainSwift object. The string passed in keyPrefix argument will be used as a prefix to all the keys used in set, get, getData and delete methods. Adding a prefix to the keychain keys can be useful in unit tests. This prevents the tests from changing the Keychain keys that are used when the app is launched manually.

Note that clear method still clears everything from the Keychain regardless of the prefix used.

let keychain = KeychainSwift(keyPrefix: "myTestKey_")
keychain.set("hello world", forKey: "hello")
// Value will be stored under "myTestKey_hello" key

Check if operation was successful

One can verify if set, delete and clear methods finished successfully by checking their return values. Those methods return true on success and false on error.

if keychain.set("hello world", forKey: "my key") {
  // Keychain item is saved successfully
} else {
  // Report error
}

To get a specific failure reason use the lastResultCode property containing result code for the last operation. See Keychain Result Codes.

keychain.set("hello world", forKey: "my key")
if keychain.lastResultCode != noErr { /* Report error */ }

Returning data as reference

Use the asReference: true parameter to return the data as reference, which is needed for NEVPNProtocol.

let keychain = KeychainSwift()
keychain.set(dataObject, forKey: "my key")
keychain.getData("my key", asReference: true)

Using KeychainSwift from Objective-C

This manual describes how to use KeychainSwift in Objective-C apps.

❗️ Known critical issue - call to action ❗️

It has been reported that the library sometimes returns nil instead of the stored Keychain value. It may be connected with the Keychain issue reported on Apple developer forums. The issue is random and hard to reproduce. If you experienced this problem feel free to create an issue and share your story, so we can find solutions.

Video tutorial

Thanks to Alex Nagy from rebeloper.com for creating this two-part video tutorial.

Keychain Swift video tutorial

Demo app

Keychain Swift demo app

Alternative solutions

Here are some other Keychain libraries.

Thanks 👍

  • The code is based on this example: https://gist.github.com/s-aska/e7ad24175fb7b04f78e7
  • Thanks to diogoguimaraes for adding Swift Package Manager setup option.
  • Thanks to glyuck for taming booleans.
  • Thanks to pepibumur for adding macOS, watchOS and tvOS support.
  • Thanks to ezura for iOS 7 support.
  • Thanks to mikaoj for adding keychain synchronization.
  • Thanks to tcirwin for adding Swift 3.0 support.
  • Thanks to Tulleb for adding Xcode 8 beta 6 support.
  • Thanks to CraigSiemens for adding Swift 3.1 support.
  • Thanks to maxkramerbcgdv for fixing Package Manager setup in Xcode 8.2.
  • Thanks to elikohen for fixing concurrency issues.
  • Thanks to beny for adding Swift 4.2 support.
  • Thanks to xuaninbox for fixing watchOS deployment target for Xcode 10.
  • Thanks to schayes04 for adding Swift 5.0 support.
  • Thanks to mediym41 for adding ability to return data as reference.
  • Thanks to AnthonyOliveri for adding ability to run unit tests from Swift Package Manager.
  • Thanks to philippec for removing deprecated access options.
  • Thanks to lucasmpaim for adding ability to return the names of all keys.

Feedback is welcome

If you notice any issue, got stuck or just want to chat feel free to create an issue. We will be happy to help you.

License

Keychain Swift is released under the MIT License.

GitHub

https://github.com/evgenyneu/keychain-swift
Comments
  • 1. WatchOS 2

    I'm wondering if setting a keychain key on iOS and trying to access it on Apple Watch is possible using this library. With WatchOS 2, Apple doesn't allow keychain sharing (using the capabilities but as far as I understand, the Apple Watch app has access to the keychain natively.

    Can you elaborate on this?

    Reviewed by acegreen at 2015-10-19 17:04
  • 2. Cannot make it to work on xcode 8 and swift 2.3 . platform tvOS

    I am using legacy framework and have everything setted up. The shared keychain is turned on, access group is setted to AppId + "." + groupIdentifier. I am using following method to write some data and it always print error

            if !keychainSwift.set(data, forKey: T.PersistorKey) {
                print("error occured")
            }
    
    Reviewed by BProg at 2016-09-27 14:54
  • 3. Cant store keys

    Hello i am trying to use the library but its not storying the keys i have this:

    
    let keychain = KeychainSwift()
                keychain.accessGroup = MyAccessGroup
                keychain.synchronizable = true
                if (keychain.set(token, forKey: "user token", withAccess: KeychainSwiftAccessOptions.AccessibleWhenUnlocked)) {
                    print(keychain.get("user token"))
                } else {
                    print("Error")
                }
    
    

    it goes to the print Error, is there somethign i have to enable in the project?

    Reviewed by antonioreyna at 2016-08-22 15:32
  • 4. carthage compile hangs

    Hi,

    trying to build with carthage (carthage update with github "marketplacer/keychain-swift" ~> 7.0 in my Cartfile), but it hangs on the ConcatenateSwiftFiles target. This is printed into the xcodebuild log file:

    === CLEAN LEGACY TARGET ConcatenateSwiftFiles OF PROJECT KeychainSwift WITH CONFIGURATION Release ==
    =
    
    Check dependencies
    
    ExternalBuildToolExecution ConcatenateSwiftFiles
        cd /Users/szotyi/Development/projects/4dmotion/iOS/4dmotion-ios/Carthage/Checkouts/keychain-swift
    
    ... # bunch of exports
    
        /Users/xxx/Carthage/Checkouts/keychain-swift/scripts/concatenate_swift_files.sh /Users/xxx/Carthage/Checkouts/keychain-swift/Sources /Users/xxx/Carthage/Checkouts/keychain-swift/Distrib/KeychainSwiftDistrib.swift //\
    //\ Keychain\ helper\ for\ iOS/Swift.\
    //\
    //\ https://github.com/marketplacer/keychain-swift\
    //\
    //\ This\ file\ was\ automatically\ generated\ by\ combining\ multiple\ Swift\ source\ files.\
    //
    

    After this line it waits forever. I would think it's something about the concatenate_swift_files.sh or the legacy target. I managed to overcome in a forked project by removing the target dependency from the scheme, but it's not the ideal solution for future releases. Thanks

    Reviewed by szotyi at 2017-01-17 13:51
  • 5. Enable "swift test" command

    Fixes https://github.com/evgenyneu/keychain-swift/issues/112

    When I forked this project, I ran into the issue linked above when running swift test on my Mac. This PR fixes the tests by adding a test target to Package.swift, and adding import statements to all of the test files.

    One thing to note is that testClear() fails with error code -25244 (errSecInvalidOwnerEdit). I believe this is due to the fact that clear() is attempting to delete everything stored in the Mac keychain (which would obviously be a bad thing). Fortunately, keychain permissions prevent this from happening with the aforementioned error. Not sure how to get that test to pass.

    Reviewed by AnthonyOliveri at 2019-09-25 17:37
  • 6. Warning clarification

    Hello, can you please clarify the warning? The answer at stackoverflow says this is a problem with the simulator. It seems to work for me without the entitlement, but a colleague had the problem, that the keychain data was lost, when updating to a new build using testflight. Any insights?

    Reviewed by bb-git at 2016-12-09 13:56
  • 7. Keychain doesn't work with XCode 8 Beta 6

    After porting my app to XCode 8 with Swift 2.3 (I waited until Beta 6 to do so), all of my tests passed with the exception of 1 set where I was storing Account information in the keychain and seeing if I could read it out. Everything I read out was nil. Note: I'm using a prefix.

    To see if this was my issue or a an issue with keychain-swift, I did the following:

    • Cloned the keychain-swift repository, checked out the Swift_2_3 branch.
    • Loaded it into XCode 8 Beta 6, selected the KeyChainSwift target and ran tests.

    What I got was a failure in KeychainWithPrefixTests.swift, line 35.

    Is there something I'm doing wrong?

    Btw, I'm not on Swift 3.0 because some other libraries I use are not yet compatible.

    Reviewed by mark-anders at 2016-09-01 14:05
  • 8. Keychain returns nil randomly

    Occasionally a nil value is returned when trying to retrieve a string from the Keychain. There's no way to reproduce it, it appears to be random. Any one else had this problem, or know a fix for this? Will probably move away from KeychainSwift if not.

    Reviewed by yusuftor at 2016-05-13 13:17
  • 9. add lock to improve concurrency usage

    TL;DR

    • add lock to improve concurrency usage
    • added tests to check concurrency usage is correct

    The change is motivated because we found a crash in the letgo app (using keychain-swift). We found out that the reason is accessing the keychain concurrently from two threads. The crash is happening in getData method when calling SecItemCopyMatching.

    We implemented some tests in ConcurrencyTests.swift. If removing the NSLock usage and running them you'll see the above mentioned crash. Contribution by @elikohen

    Reviewed by ahernandezlopez at 2017-10-27 11:58
  • 10. get always returning nil

    i did the manual install by copying the KeychainSwiftDistrib.swift file into my project but i always get nil when i run the code below. I've tried with/without the access qualifier. am i missing something?

        let keychain = KeychainSwift()
    
        keychain.accessGroup = "CS671JRA62.com.myapp.KeychainGroup"
    
        keychain.set("Hello world", forKey: "my key", withAccess: .AccessibleAfterFirstUnlock)
    
        let testValue = keychain.get("my key")
    
    Reviewed by geigerzaehler242 at 2015-12-18 22:20
  • 11. Added Access options to the get parameters with a default option set.

    Added Access options to the get parameters with a default option set. As posted in:

    https://github.com/evgenyneu/keychain-swift/issues/78#issuecomment-549045569

    This provides a way for the developer to specify the same accessibility level that they saved the keychain item as to query out the keychain item. By default it is set to when unlocked, but it can be default to be afterFirst unlock to be able to access in the background

    Also Added some basic tests to validate the passing of the access options for the get parameter.

    Reviewed by robertbarclay at 2019-11-02 14:30
  • 12. How to disable keychain data recovery from iCloud backup

    • Device A creates a token write through the following options
    kSecAttrAccessible = kSecAttrAccessibleAlwaysThisDeviceOnly
    kSecAttrSynchronizable = kSecAttrSynchronizableAny
    
    • Device A creates an iCloud backup
    • Device B erases or reflashes the firmware
    • Device B selects the iCloud backup created by Device A to restore
    • After the recovery of Device B is completed, the application can read the token written by Device A
    • I want to disable the ability to read tokens created by other devices after restoring from the iCloud backup of other devices, what should I do?
    Reviewed by 0x1306a94 at 2022-06-23 07:01
  • 13. Refactor thread safety of KeychainSwift class

    Switched NSLock to NSRecursiveLock to avoid the need for an internal deleteNoLock() method and remove it.

    NSRecursiveLock is conform to the same NSLocking protocol as NSLock but the fundamental difference is that NSRecursiveLock allows locking resources recursively. The main rule here is .unlock() calls must be as much as .lock() calls. That is why we no more need the internal deleteNoLock method, which was added, as I suppose, to avoid deadlock.

    • KeychainSwiftDistrib.swift file - updated
    • All tests passed
    Screenshot 2022-05-11 at 16 17 00
    Reviewed by vdshko at 2022-05-11 13:45
  • 14. Added macos support

    Hi @evgenyneu! thank you for keychain-swift. It saves my time!

    But I want to share with you some behavior for macOS.

    There was a problem:

    I am using keychain in my macOS app to store jwt tokens (access and refresh)(kSecClassGenericPassword) and I have figured out that I can't manage existed data via the same app with another name. I have built two equal applications with different app names:

    for example App1.app and App2.app Note: it's the same build, but with only a different - app file name.

    And if I create the keychain item using the first app (App1.app) I can't remove it from the second one.

    If I double click on the keychain item in Keychain Access default App I can see that there is only one app in Access Control tab (with the name App1.app).

    The Solution

    Finally, I have found the solution in this article: Making macOS Keychain behave as iOS keychain

    And have made a pull request based on this article.

    Reviewed by bananaRanger at 2022-05-07 08:05
  • 15. Added support for Keychain Access Flags which are available since iOS 12, for added security.

    I needed the Access control flag to set .biometricCurrentSet as per security guidelines that prevents Keychain Bypass vulnerability. Reference the following document:

    https://github.com/sensepost/objection/wiki/Understanding-the-iOS-Biometrics-Bypass

    You can ignoring merging it to main branch. Just sharing it so if others find it helpful, they can use this fork directly. Kudos for making the wrapper super user friendly.

    Reviewed by UdoySoumik at 2022-03-15 23:37
  • 16. Please use semantic versioning

    It looks like you have released 19 incompatible versions. Maybe you have but maybe you should just use semantic versioning. See https://semver.org

    This just count up major versions approach breaks a lot of tools.

    Reviewed by roddi at 2021-11-11 15:22
  • 17. Error installing Swift Package

    Hi, thanks for sharing this package. I tried to install via Swift Package but got the error below stating "keychain swift could not be resolved" Could you kindly help me out?

    スクリーンショット 2021-11-05 11 35 46
    • Library setup method: Swift Package Manager.
    • Xcode version: 13
    • OS version: MacOS Big Sur 11.6
    Reviewed by hiropome at 2021-11-05 02:42
A wrapper to make it really easy to deal with iOS, macOS, watchOS and Linux Keychain and store your user's credentials securely.

A wrapper (written only in Swift) to make it really easy to deal with iOS, macOS, watchOS and Linux Keychain and store your user's credentials securely.

Mar 29, 2022
Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS.
Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS.

KeychainAccess KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X. Makes using Keychain APIs extremely easy and much mor

Jun 22, 2022
A simple Swift Keychain Wrapper for iOS, watchOS, and OS X.

Latch A simple Swift 2.0 Keychain Wrapper for iOS, watchOS 2, and OS X. Usage A proper example of how to use Latch can be seen in the tests. import La

Jan 29, 2022
Helper/wrapper for mautrix-imessage for jailbroken devices

Brooklyn This readme is out-of-date. Blame Ethan, he's working on it. Components Rubicon "The die is cast." Crosses Apple's last river between IMCore

May 17, 2022
Simple Objective-C wrapper for the keychain that works on Mac and iOS

SAMKeychain SAMKeychain is a simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system Keyc

Jun 15, 2022
Generate passwords and save them in Keychain. Made with SwiftUI.
Generate passwords and save them in Keychain. Made with SwiftUI.

lockd Generate strong passwords and save them in Keychain. Join lockd Beta on TestFlight: https://testflight.apple.com/join/xJ5AlvS3 Features: Generat

Jun 6, 2022
A simple wrapper for the iOS Keychain to allow you to use it in a similar fashion to User Defaults. Written in Swift.

SwiftKeychainWrapper A simple wrapper for the iOS / tvOS Keychain to allow you to use it in a similar fashion to User Defaults. Written in Swift. Prov

Jun 25, 2022
A powerful, protocol-oriented library for working with the keychain in Swift.

Locksmith A powerful, protocol-oriented library for working with the keychain in Swift. ?? iOS 8.0+ ?? Mac OS X 10.10+ ⌚️ watchOS 2 ?? tvOS ?? I make

Jun 17, 2022
KeyClip is yet another Keychain library written in Swift.

KeyClip KeyClip is yet another Keychain library written in Swift. Features Multi Types ( String / NSDictionary / NSData ) Error Handling Settings ( kS

Feb 2, 2022
A really simple key-value wrapper for keychain.

PlainKeychain A really simple key-value wrapper for keychain. Features ✅ Key-value pairs using kSecClassGenericPassword. ❌ Internet passwords (kSecCla

Nov 27, 2021
The IDAGIO WatchOS app using swift
The IDAGIO WatchOS app using swift

IDAGIORedesignWatchOS I redesigned the IDAGIO WatchOS app as an exercise Old App

Dec 23, 2021
Virgil Core SDK allows developers to get up and running with Virgil Cards Service API quickly and add end-to-end security to their new or existing digital solutions to become HIPAA and GDPR compliant and more.
Virgil Core SDK allows developers to get up and running with Virgil Cards Service API quickly and add end-to-end security to their new or existing digital solutions to become HIPAA and GDPR compliant and more.

Virgil Core SDK Objective-C/Swift Introduction | SDK Features | Installation | Configure SDK | Usage Examples | Docs | Support Introduction Virgil Sec

Aug 11, 2021
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

May 31, 2022
Safe and easy to use crypto for iOS and macOS

Swift-Sodium Swift-Sodium provides a safe and easy to use interface to perform common cryptographic operations on macOS, iOS, tvOS and watchOS. It lev

Jun 15, 2022
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

May 31, 2022
Native and encrypted password manager for iOS and macOS.
Native and encrypted password manager for iOS and macOS.

Open Sesame Native and encrypted password manager for iOS and macOS. What is it? OpenSesame is a free and powerful password manager that lets you mana

Jun 26, 2022
Oversecured Vulnerable iOS App is an iOS app that aggregates all the platform's known and popular security vulnerabilities.

Description Oversecured Vulnerable iOS App is an iOS app that aggregates all the platform's known and popular security vulnerabilities. List of vulner

Jun 21, 2022
PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. PGPro is made in Switzerland.
PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. PGPro is made in Switzerland.

PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. P

Jun 24, 2022
Simple, secure password and data management for individuals and teams

Padloc Simple, secure password and data management for individuals and teams (formerly known as Padlock). This repo is split into multiple packages: P

Jun 20, 2022