Keychain
Keychain provides secure access to the system keychain for storing sensitive and persistent data inside the Scripting environment. It is designed for:
- Authentication tokens
- Login credentials
- License and subscription states
- Encryption keys
- Private user data
All data is protected using the system-level Keychain security mechanism.
1. Per-Script Keychain Scope
In Scripting, Keychain uses a per-script isolation model.
1.1 Scope Rules
-
Each script has its own independent Keychain scope
-
A script can only access the Keychain data it has written
-
Different scripts:
- Cannot read each other’s Keychain data
- Cannot overwrite each other’s keys
- Even if the same key name is used
- Even if
synchronizable: trueis enabled
-
Each script is treated as an independent security sandbox
1.2 Security Implications
This design ensures that:
- No script can steal credentials from another script
- Subscription, login state, and authorization data are fully isolated
- Malicious scripts cannot access private user data stored by other scripts
- The security boundary is stricter than the system-level app Keychain alone
1.3 Script Removal Behavior
-
When a script is deleted:
- All Keychain data under that script’s scope is automatically removed
-
Other scripts’ Keychain data is not affected
2. Namespace
3. Supported Data Types
Keychain supports three data types:
4. KeychainAccessibility
The default depends on whether iCloud synchronization is enabled:
When synchronizable: true is used, passcode, unlocked_this_device, and first_unlock_this_device are not allowed because they have ThisDeviceOnly semantics and cannot synchronize to other devices. Writes with these combinations fail and return false.
5. iCloud Synchronization (synchronizable)
Default:
When enabled, Keychain items use the migratable default accessibility policy first_unlock. If you customize accessibility, use a synchronizable policy such as unlocked or first_unlock.
Even when enabled, synchronization is still restricted to the current script scope.
6. Writing Data
6.1 Store a String
6.2 Store a Boolean
6.3 Store Binary Data
6.4 Overwrite Rules
- Existing values are automatically overwritten
trueis returned on successfalseis returned on failure
7. Reading Data
7.1 Read a String
7.2 Read a Boolean
7.3 Read Binary Data
8. Removing Data
- If the key exists, it is deleted and returns
true - If the key does not exist, it still safely returns
true
9. Checking for Key Existence
10. Listing All Keys
11. Clearing the Keychain
Behavior:
- Only clears data within the current script scope
- Does not affect other scripts
- Does not affect the app’s own Keychain data or other apps
12. synchronizable Read/Write Consistency Rules
If a key is written with:
Then all subsequent operations must use the same flag:
13. Security Recommendations
Suitable Data
- Authentication tokens
- Subscription and license states
- User identifiers
- Encryption keys
Not Recommended
- Large binary files
- High-frequency cache data
- Public configuration values
14. Typical Usage Examples
Pick a Keychain Value
pick(options?: { title?: string; prompt?: string }): Promise<string | null> opens a searchable, single-selection sheet. title sets its navigation title and prompt displays instructions above the list. Both are optional; blank text uses the default title or omits the prompt.
The user must explicitly enable local authentication if needed, and authenticate for every picker visit. The sheet identifies the calling script. Tap a key to select it, then tap Confirm at the top right to share its current value with the calling script. Confirm appears only after selection. Selecting a row alone does not read or return its value. Changing the search clears the selection.
The picker includes script, skill, workspace and execution scopes, including old script scopes. Shared storage and internal application credentials are excluded. It does not edit, delete, preview or copy values.
Closing or cancelling the sheet, cancelling authentication, or moving the app to the background returns null. An empty string remains "". Values must decode as UTF-8, matching Keychain.get(). Read failures and non-UTF-8 data are shown in the sheet so the user can retry, choose another key or cancel.
This API requires a foreground app with an available presentation window. Unsupported contexts (such as widgets or background execution), invalid argument types and concurrent picker requests reject with an error. Script termination dismisses the picker and releases the request; a terminated JavaScript context cannot receive a result. Each selection is a one-time disclosure and does not grant ongoing access to another script's keys.
