iOS keychain
app security
unique keychain items
iOS development
mobile security

What makes a keychain item unique in iOS?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In the iOS Keychain, uniqueness is not based on one universal "primary key" field. It depends on the keychain item class and the set of attributes that class uses to identify duplicates.

Uniqueness is defined by the item class

Keychain Services stores several classes of items, such as generic passwords, internet passwords, certificates, keys, and identities. Each class has its own identifying attributes.

For generic password items, the most commonly used identifying attributes are the item class plus values such as kSecAttrService and kSecAttrAccount. For internet passwords, uniqueness usually depends on a richer combination such as server, account, protocol, path, and port.

That is why two keychain inserts that look "similar" to a human can behave differently depending on which attributes are present. If the identifying attributes match an existing item, SecItemAdd can fail with errSecDuplicateItem.

A practical generic-password example

The most common app case is a generic password entry keyed by service and account.

swift
1import Security
2
3func savePassword(_ password: String, service: String, account: String) -> OSStatus {
4    let data = Data(password.utf8)
5
6    let query: [String: Any] = [
7        kSecClass as String: kSecClassGenericPassword,
8        kSecAttrService as String: service,
9        kSecAttrAccount as String: account,
10        kSecValueData as String: data
11    ]
12
13    return SecItemAdd(query as CFDictionary, nil)
14}

If you call this twice with the same class, service, and account, the second add will usually be treated as a duplicate. If you want to change the value, the right operation is often SecItemUpdate, not another SecItemAdd.

Why developers get confused

The confusion usually comes from thinking the keychain item is unique because of the secret value itself or because of one attribute like account name. Neither is generally true on its own. The identifying set depends on the class and query attributes the Security framework uses internally.

Another source of confusion is access-related attributes. Things like accessibility, synchronizable state, and access group affect how and where the item can be used, but they are not the same question as the item's logical identity from the app's point of view.

That distinction matters because a duplicate-item error is usually telling you about identity attributes, not about encryption strength or access control.

Update-versus-insert is part of the design

A clean keychain workflow usually has three operations:

  1. add a new item
  2. read an existing item
  3. update that existing item when the secret changes

Trying to use SecItemAdd for every save is what often triggers the uniqueness question in the first place. A better pattern is to search using the identifying attributes and then update the existing record when appropriate.

Think in terms of your app's key

At the application level, you should decide what logically identifies the secret. For many apps that is "service plus account." Once you choose that, keep it consistent across add, fetch, and update queries so the keychain behaves predictably.

If you change the identifying attributes accidentally between calls, you can create what looks like duplicate secrets even though the keychain considers them separate items.

Common Pitfalls

  • Assuming the secret value itself determines uniqueness.
  • Treating kSecAttrAccount alone as the whole identity for every keychain class.
  • Repeatedly calling SecItemAdd when the intended operation is really an update.
  • Mixing identifying attributes between save and lookup queries.
  • Confusing access-control attributes with the attributes that define item identity.

Summary

  • Keychain uniqueness depends on the item class and that class's identifying attributes.
  • For generic passwords, service and account are common identity fields.
  • A duplicate add usually means the identifying attributes already match an existing item.
  • Updating an existing secret should usually use SecItemUpdate, not another insert.
  • Choose a consistent app-level identity scheme so add, read, and update logic all agree.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.