Token Storage
Perhaps one of the most important aspects of the token management system, the token storage interface is used to perform basic CRUD operations to securely store tokens in a thread-safe fashion.
The underlying implementation may vary depending on the environment (e.g. within Swift there are separate implementations for Apple vs Linux platforms), so there may be multiple classes that conform to this interface within a single language.
Primary workflows
List all token IDs
All tokens are uniquely identified using a locally-generated identifier (e.g. a UUID). Since tokens may need to be stored using encryption or biometric security settings, it may not be possible to simply iterate over a collection of token data within a database or a file. Therefore, the ability to retrieve a list of token IDs without needing to prompt a user for biometrics is critical.
It's important that only token IDs should be returned where both the token data, and its metadata, can be located. This is only applicable if these values are stored separately.
Add a new token
This is used to add a new token to storage, optionally with a list of developer-assigned tags and security options (dependent on the environment). The Token and Metadata objects may be stored separately, depending on the environment, to allow for different security contexts when enumerating tokens vs retrieving their sensitive contents.
This is intended to only be used to add a new token. If an existing token exists with the new ID, this should result in an error / exception
The implementation of this function should detect if this token is the first token within storage (e.g. if no other tokens exist in storage prior to this function being called, or if allIDs was empty at the start of the function). If this is the case, the local Default ID should be set, and the CredentialCoordinator should be notified that the default value has changed.
Get a token
Returns the token from storage using the given token ID, and optionally using some sort of authentication context as needed by the environment (e.g. to supply biometric or local authentication context).
Exceptions should be thrown if a token is not found with the given ID. It's important to note that downstream consumers should intercept this error, but it should be expected that a token exists if this function is called with a token ID.
Update an existing token
Replaces the token in storage with the new token supplied, and optionally with the given security settings depending on the environment. If no security settings are supplied, the previous settings used when initially storing the token should be reused (e.g. the security context should not change).
Additionally, since the token's ID is a locally-generated unique value used to disambiguate multiple stored tokens, the supplied token object may not have a valid token ID (e.g. it may have just come in from a refresh operation). As such, before serializing the token to be stored, its ID should be updated to match the value of the token being replaced.
Finally, the OAuth2 specification does not provide an absolute "Issued At" date that can be used as a reference point when calculating expiration; the issued date is assumed to be whatever client's local system time indicates, and all expiration times are represented as offsets from that time. As such, if the token supplied to this function does not have an issuedAt date, the client's current coordinated time should be used instead.
Get the default token ID
Returns the Token ID currently assigned as the default, or null if no default is assigned yet.
This value should be loaded lazilly to prevent issues during app launch.
Set the default token ID
Sets the ID of the token that should be considered the default. A value of null is valid, since it's possible for one or more tokens to be stored without an explicit default defined.
Once the value has been saved, the CredentialCoordinator should be notified that the default token ID has changed.
Get a token's metadata
When a token is stored, it also stores a separate TokenMetadata object that represents additional information about the token, its uses, and data used to query / filter a token.
This function is used to retrieve that metadata for the purposes of enumerating stored credentials.
Update a token's metadata
Updates the metadata associated with a token in storage. This is usually used when a developer sets the tags for a credential after its been stored.
Remove a token
Removes a token, and its metadata, from storage. Once the token has been successfully removed, it should notify the CredentialCoordinator. Additionally, if the removed token was assigned as the default token, the default token ID should be set to null.