Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Swift Keychain Class
import UIKit
import Security
let serviceIdentifier = "com.company"
let accessGroup = "com.company.app"
let kSecClassValue = kSecClass as NSString
let kSecAttrAccountValue = kSecAttrAccount as NSString
let kSecValueDataValue = kSecValueData as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword as NSString
let kSecAttrServiceValue = kSecAttrService as NSString
let kSecMatchLimitValue = kSecMatchLimit as NSString
let kSecReturnDataValue = kSecReturnData as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne as NSString
class KeychainService: NSObject {
class func setString(value: NSString, forKey: String) {
self.save(serviceIdentifier, key: forKey, data: value)
}
class func stringForKey(key: String) -> NSString? {
var token = self.load(serviceIdentifier, key: key)
return token
}
class func removeItemForKey(key: String) {
self.save(serviceIdentifier, key: key, data: "")
}
class func save(service: NSString, key: String, data: NSString) {
var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// Instantiate a new default keychain query
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])
// Delete any existing items
SecItemDelete(keychainQuery as CFDictionaryRef)
if data == "" { return }
// Add the new keychain item
var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
}
class func load(service: NSString, key: String) -> NSString? {
// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
var dataTypeRef :Unmanaged<AnyObject>?
// Search for the keychain items
let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
let opaque = dataTypeRef?.toOpaque()
var contentsOfKeychain: NSString?
if let op = opaque? {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
// Convert the data retrieved from the keychain into a string
contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
} else {
return nil
}
return contentsOfKeychain
}
}
@ghost

This comment has been minimized.

Copy link

ghost commented Aug 10, 2014

Having issues with KeychainService.saveToken("token") and KeychainService.loadToken() from Matt Palmer's original post. When trying to implement saveToken, it basically tells me that is not found in KeychainService. If the replacements made also changed the calls, could you point me to those. Thanks.

@matthewpalmer

This comment has been minimized.

Copy link

matthewpalmer commented Aug 10, 2014

@dvdowns I've updated the code in my post to use Swift's new access control modifiers, along with the changes in this gist. Please let me know if it works for you :) (I haven't had a chance to grab the latest beta version yet)

@gustaflindqvist

This comment has been minimized.

Copy link

gustaflindqvist commented Aug 19, 2014

This solution is having issues in beta 6. You can only access kSecClass.__conversion() etc.

@AsceticMonk

This comment has been minimized.

Copy link

AsceticMonk commented Oct 3, 2014

Now, __conversion() is also removed.

@alexbosworth

This comment has been minimized.

Copy link
Owner Author

alexbosworth commented Oct 8, 2014

I updated the code for XCode 6.0 GM -- however I'm running into an issue where it only works when building for Debug not for Release, tracking that down

@alexbosworth

This comment has been minimized.

Copy link
Owner Author

alexbosworth commented Oct 8, 2014

OK fair warning, the code above only works if the Swift Compiler - Code Generation level is set at "none", not at "Fastest" which is the default

Make sure to test the code against your release scheme

@superarts

This comment has been minimized.

Copy link

superarts commented Nov 22, 2014

I can confirm the issue @alexbosworth mentioned exists in xcode 6.1 as well. Nice catch dude!

@deniskr

This comment has been minimized.

Copy link

deniskr commented Dec 3, 2014

I have developed a Swift wrapper over the entire C Keychain API. See if it can be useful for you: https://github.com/deniskr/KeychainSwiftAPI

@alexbosworth

This comment has been minimized.

Copy link
Owner Author

alexbosworth commented Dec 30, 2014

Another note about this, if you are using this code and you want the keys to be accessible from the lockscreen, like in a background fetch, you need to adjust the kSecAttrAccessible value

@chiliec

This comment has been minimized.

Copy link

chiliec commented Sep 28, 2015

up! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.