Okta Secure Storage Library
This library is a Swift wrapper around the iOS LocalAuthentication
and Security
frameworks. The library provides convenient APIs to utilize keychain services by giving your app a mechanism to store small bits of user data in an encrypted database. The keychain is not limited to passwords and tokens. You can store other secrets that the user explicitly cares about, such as credit card information or even short notes.
The storage library includes the following features:
- Get, set and delete keychain items.
- Store to the keychain behind a biometric factor such as fingerprint or Face ID.
Table of Contents
- Usage
- Create instance of OktaSecureStorage class
- Save data to keychain
- Save data to keychain behind a biometric factor
- Load data from keychain
- Delete data from keychain
- API Reference
- How to use this libary in Objective-C project
- Contributing
Usage
Add import OktaSecureStorage
to your source code.
OktaSecureStorage
class
Create instance of let oktaStorage = OktaSecureStorage()
or
let oktaStorage = OktaSecureStorage(applicationPassword: "user_password")
Save data to keychain
do {
try oktaStorage.set(string: "password", forKey: "jdoe")
} catch let error {
// Handle error
}
Save data to keychain behind a biometric factor
do {
try oktaStorage.set(string: "password", forKey: "jdoe" behindBiometrics: true)
} catch let error {
// Handle error
}
Load data from keychain
do {
let password = try oktaStorage.get("jdoe")
} catch let error {
// Handle error
}
Also, if you need to know what keys are already stored:
do {
let keys = try oktaStorage.getStoredKeys()
} catch let error {
// Handle error
}
Delete data from keychain
do {
try oktaStorage.delete("jdoe")
} catch let error {
// Handle error
}
API Reference
init(applicationPassword:)
Initializes OktaSecureStorage instance. The optional parameter applicationPassword
allows items in the keychain to be secured using an additional password. This way, if the user does not have a passcode or Touch ID set up, the items will still be secure, and it adds an extra layer of security if they do have a passcode set
set(string:forKey:)
Stores an item securely in the keychain. Method returns true on success and false on error.
do {
try oktaStorage.set("password", forKey: "jdoe")
} catch let error {
// Handle error
}
set(string:forKey:behindBiometrics:)
Stores an item securely and additionally accepts behindBiometrics
parameter. Set this parameter to true
if you want to store keychain item behind a biometric factor such as touch ID or face ID.
do {
try oktaStorage.set("password", forKey: "jdoe" behindBiometrics: true)
} catch let error {
// Handle error
}
set(string:forKey:behindBiometrics:accessGroup:)
Stores an item securely and additionally accepts accessGroup
identifier. Use accessGroup
to share keychain items between apps. Two or more apps that are in the same group can share keychain items because they share a common keychain access group entitlement. For more details, see Sharing Access to Keychain Items Among a Collection of Apps
do {
try oktaStorage.set("password",
forKey: "jdoe",
accessGroup: "TEAMSEEDID.com.mycompany.sharedkeychain")
} catch let error {
// Handle error
}
set(string:forKey:behindBiometrics:accessibility:)
Stores an item securely and additionally accepts accessibility
parameter. Use accessibility
parameter to indicate when a keychain item is accessible. Choose the most restrictive option that meets your app’s needs so that the system can protect that item to the greatest extent possible. Possible values are listed here. Please note that default value for accessibility parameter is kSecAttrAccessibleWhenUnlockedThisDeviceOnly - items with this attribute do not migrate to a new device.
do {
try oktaStorage.set("password",
forKey: "jdoe",
accessibility: kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
} catch let error {
// Handle error
}
Additional helper functions
set(string: String,
forKey key: String,
accessGroup: String? = nil,
accessibility: CFString?) throws
set(data: Data,
forKey key: String) throws
set(data: Data,
forKey key: String,
behindBiometrics: Bool) throws
set(data: Data,
forKey key: String,
behindBiometrics: Bool,
accessGroup: String) throws
set(data: Data,
forKey key: String,
behindBiometrics: Bool,
accessibility: CFString) throws
set(data: Data,
forKey key: String,
accessGroup: String?,
accessibility: CFString?) throws
get(key:biometricPrompt:)
Retrieves the stored keychain item from the keychain. Additionally method expects optional prompt
message for the keychain item stored behind a biometric factor.
- Note: iOS will show native Touch ID or Face ID message view in case of biometrics enabled storage. It means that function may be blocked and wait for the user's action. It is advised to call
get
function in a background thread
DispatchQueue.global().async {
do {
let password = try oktaStorage.get("jdoe", prompt: “Please use Touch ID or Face ID to sign in”)
} catch let error {
// Handle error
}
}
getData(key:biometricPrompt:)
Retrieves the stored keychain item from the keychain. Additionally method expects optional prompt
message for the keychain item stored behind a biometric factor.
- Note: iOS will show native Touch ID or Face ID message view in case of biometrics enabled storage. It means that function may be blocked and wait for the user's action. It is advised to call
getData
function in a background thread
DispatchQueue.global().async {
do {
let passwordData = try oktaStorage.getData("jdoe", prompt: “Please use Touch ID or Face ID to sign in”)
} catch let error {
// Handle error
}
}
getStoredKeys(biometricPrompt:accessGroup:)
Retrieves previously stored keys from the keychain. Additionally method expects optional prompt
message for the keychain item stored behind a biometric factor. Use accessGroup
to access shared keychain items between apps.
- Note: Similarly to
getData
function, iOS will show native Touch ID or Face ID message view in case of biometrics enabled storage. It means that function may be blocked and wait for the user's action. It is advised to callgetStoredKeys
function in a background thread.
DispatchQueue.global().async {
do {
let keys = try oktaStorage.getStoredKeys()
} catch let error {
// Handle error
}
}
delete(key:)
Removes the stored keychain item from the keychain
do {
try oktaStorage.delete("jdoe")
} catch let error {
// Handle error
}
clear()
Removes all keychain items from the keychain
do {
try oktaStorage.clear()
} catch let error {
// Handle error
}
isTouchIDSupported
Checks whether device enrolled with Touch ID. If the biometry is not available, not enrolled or locked out, then the function call will return false.
let isTouchIDSupported = storageManager.isTouchIDSupported()
isFaceIDSupported
Checks whether device enrolled with Face ID. If the biometry is not available, not enrolled or locked out, then the function call will return false.
let isFaceIDSupported = storageManager.isFaceIDSupported()
How to use this library in Objective-C project
- Include auto generated swift header file into your .m file. Swift header file contains objective-c representation of Okta swift classes. Please note that the name of header file consists of your project name and “-Swift” suffix. For example if your project name is AuthApp, then auto generated header file name will be “AuthApp-Swift.h”
- Start using programming components available in swift header file
Example:
OktaSecureStorage *storage = [OktaSecureStorage new];
NSError *error;
BOOL success = [storage setWithString:"password" forKey:"jdoe" error:&error];
if (success) {
NSString *password = [storage getWithKey:@"jdoe" error:&error];
if (password != nil) {
success = [storage deleteWithKey:@"jdoe" error:&error];
}
}
Contributing
We're happy to accept contributions and PRs! Please, read contributing guide.