Skip to content

Instantly share code, notes, and snippets.

@kezzico
Created August 29, 2018 22:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kezzico/66d7414bd0436fbbe8e744004abbce7e to your computer and use it in GitHub Desktop.
Save kezzico/66d7414bd0436fbbe8e744004abbce7e to your computer and use it in GitHub Desktop.
Token Storage in Swift
//
// Token.swift
//
// Created by Lee Irvine on 8/29/18.
// Copyright © 2018 kezzi.co. All rights reserved.
//
import Foundation
import Security
struct TokenError: Error {
let message: String
}
class Token: NSObject {
private class func tokenId() -> String! {
guard let appId = Bundle.main.bundleIdentifier else {
print("Token: App ID missing from Bundle")
return nil
}
return "\(appId).token"
}
class func set(_ value: String, server: String) {
var query = [String: Any]()
query[kSecClass as String] = kSecClassInternetPassword
query[kSecAttrAccount as String] = self.tokenId()
query[kSecAttrServer as String] = server
query[kSecValueData as String] = value.data(using: .utf8)
// Must delete. Not possible to explicitly overwrite.
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
if status != errSecSuccess {
print("failed to store key \(status)")
}
}
class func get(server: String) -> String? {
var query = [String: Any]()
query[kSecClass as String] = kSecClassInternetPassword
query[kSecAttrAccount as String] = self.tokenId()
query[kSecAttrServer as String] = server
query[kSecReturnData as String] = true
query[kSecReturnAttributes as String] = true
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
if status == errSecItemNotFound {
return nil
}
guard status == errSecSuccess else {
print("Token: failed to load key \(status)")
return nil
}
guard let existingItem = item as? [String : Any] else {
print("Token: no token found in keychain")
return nil
}
guard let tokenData = existingItem[kSecValueData as String] as? Data else {
print("Token: token data missing")
return nil
}
guard let token = String(data: tokenData, encoding: .utf8) else {
print("Token: failed to decode token")
return nil
}
return token
}
class func destroy(server: String) {
var query = [String: Any]()
query[kSecClass as String] = kSecClassInternetPassword
query[kSecAttrAccount as String] = self.tokenId()
query[kSecAttrServer as String] = server
SecItemDelete(query as CFDictionary)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment