Shared web credentials is a programming interface that enables native iOS apps to share credentials with their website counterparts. For example, a user may log in to a website in Safari, entering a user name and password, and save those credentials using the iCloud Keychain. Later, the user may run a native app from the same developer, and instead of the app requiring the user to reenter a user name and password, shared web credentials gives it access to the credentials that were entered earlier in Safari. The user can also create new accounts, update passwords, or delete her account from within the app. These changes are then saved and used by Safari.
Language
- Swift
- Objective-C
Overview
Note
Accessing shared web credentials requires permission from the app, the website, and the user.
The shared web credentials API defines Core Foundation–based functions for storing and requesting shared password-based credentials. There are four steps to sharing credentials:
Add a
com.apple.developer.associated-domainsentitlement to your app. This entitlement must include all the domains with which you want to share credentials.Add an
apple-app-site-associationfile to your website. This file must include application identifiers for all the apps with which the site wants to share credentials.When the app is installed, the system downloads and verifies the site association file for each of its associated domains. If the verification is successful, the app is associated with the domain.
An app can share credentials with any associated domains by calling
SecAddSharedWebCredential(_:_:_:_:)andSecRequestSharedWebCredential(_:_:_:).
Adding the Associated Domains Entitlement
To enable shared credentials in your app, add the com.apple.developer.associated-domains key to your app’s entitlements. You can add this entitlement using the target’s capabilities pane (see Figure 1).
Include a list of all the domains with which your app wants to share credentials. Keep the number of domains to about 20 to 30. To match all subdomains of an associated domain, you can specify a wildcard by prefixing *. before the beginning of a specific domain (the period is required).
Each domain you specify uses the following format:
<service>:<fully qualified domain>[:port number]
For shared web credentials, always use the webcredentials service.
Adding the associated domains for your app

Note
Both shared web credentials and Handoff use the associated domains. Shared web credentials use the webcredentials service, while Handoff uses the activitycontinuation service. For more information about Handoff, see Handoff Programming Guide.
Adding the Site Association File
Place your apple-app-site-association file on a website that matches one of the domains in your app’s associated domains entitlement (you can also place it in the .well-known subdirectory). The file’s URL should match the following format:
https://<fully qualified domain>/apple-app-site-association
The file’s JSON content must contain a webcredentials dictionary with an apps array. The apps array lists the application identifiers for all the apps that can access the shared credentials for this site. For an example, see Listing 1.
Server-side web credentials
{
"webcredentials": {
"apps": [ "D3KQX62K1A.com.example.DemoApp",
"D3KQX62K1A.com.example.DemoAdminApp" ]
}
}
The apple-app-site-association file must meet the following requirements:
The file must be hosted on an
https://site with a valid certificate (for example, Safari must not issue a certificate warning when viewing the site).The file must not use any redirects.
In iOS 9.3.1 and later, the file must be no larger than 128 KB (uncompressed), regardless of whether it is signed.
If your app runs in iOS 9 and later and you use HTTPS to serve the file, you can create a plain text file that uses the
application/jsonMIME type and you don’t need to sign it.If your app runs in iOS 8, the file must have the MIME type
application/pkcs7-mimeand it must be CMS signed by a valid TLS certificate.
You can sign the JSON file using Terminal commands such as those shown in Listing 2. The echo command puts the server-side web credentials from Listing 2 into a file named json.txt, removing most of the white space from the text to minimize the required bandwidth. The line beginning with the cat command reads the file and pipes the output to the openssl command, which signs the file using the certificate and key for an identity valid for example.com.
Signing the credentials file
echo '{"webcredentials":{"apps":["D3KQX62K1A.com.example.DemoApp",
"D3KQX62K1A.com.example.DemoAdminApp"]}}' > json.txt
cat json.txt | openssl smime -sign -inkey example.com.key
-signer example.com.cert
-certfile intermediate.cert
-noattr -nodetach
-outform DER > apple-app-site-association
The output of the openssl command is the signed JSON file that you put on your website at the apple-app-site-association URL, in this example https://example.com/apple-app-site-association.
The certificate used to sign the JSON file must meet the following requirements:
The certificate must be a valid TLS certificate for the domain name. For example, the certificate must have a Common Name or Subject Alternative Name that matches the domain (example.com in the example).
The certificate must not be expired.
The server’s certificate chain must lead to a root certificate issued by a certificate authority (CA) trusted by iOS.
Note
The identity used to sign the file does not need to be the same identity used by the web server to host the file.
For the complete list of certificate authorities trusted by iOS, see the Apple support article Lists of available trusted root certificates in iOS.
Validating the Site Association File
When the app is installed, iOS attempts to associate it with all the domains listed in its associated domains entitlement. iOS performs the following steps:
Takes each domain from the associated domains element.
Appends
“/apple-app-site-association”to the end of the domain, and downloads the contents at the resulting URL.Verifies the JSON file’s signature.
Makes sure the JSON file includes the app’s application identifier.
If all of these steps succeed, the app is associated with the domain and you can use SecAddSharedWebCredential(_:_:_:_:) and SecRequestSharedWebCredential(_:_:_:) to access and modify the shared web credentials. After an app is successfully associated with a domain, it remains associated until the app is deleted from the device.
Note
If your site uses different subdomains (such as example.com, www.example.com, and support.example.com) each requires its own entry in the com.apple.developer.associated-domains entitlement, and each must serve its own /apple-app-site-association file. The signing identity can be for *.example, if so issued by your certificate authority (CA).
A number of issues might cause the validation to fail.
The JSON signature is invalid. The association is denied.
JSON file is invalid or does not contain the application identifier. The association is denied.
The server returns a 300-499 code. This includes redirects. The association is denied.
The server returns a 500-599 code. The system assumes that the file is temporarily unavailable and tries again. By default, the system tries every 3 hours for up to eight tries. It also tries whenever the app calls the
SecAddSharedWebCredential(_:_:_:_:)orSecRequestSharedWebCredential(_:_:_:)method.
Sharing Credentials
There are a wide range of common situations where you may want to use shared web credentials. This section covers four: logging in to a remote server, creating a user account in the app, changing a user’s password, and deleting a user’s account.
Logging In to a Remote Server
Typically, when an app needs to log in to a remote service, you start by checking for the user’s credentials in the iOS keychain. If you have current credentials for the user, you can log them in directly. If not, prompt the users for their user name and password, and then try to log them in. You will also want to save their credentials after the login is successful. This workflow is shown in Figure 2.
Basic login workflow

When using shared web credentials, you add two steps to this procedure. As before, you start by checking if the user’s credentials are stored in the keychain. If you cannot find the user’s credentials, you check for shared web credentials. If you still cannot find any credentials, or if the user declines to use the shared credentials, you must prompt the user for her name and password. Try to log the user in, and if the login is successful, save the credentials to both the keychain and the shared web credentials. This ensures that the user has access to the credentials in Safari as well as within your app. This workflow is shown in Figure 3.
Login workflow with shared web credentials

Remember
Even if the system finds a match in the shared web credentials, the user can still decline to use those credentials. This will cause the check for shared web credentials to fail. Therefore, you must always have a fallback that prompts the user for their name and password.
Do not use the shared web credentials as your primary storage for secure user credentials. Instead, save the user’s credentials in the keychain, and only use the shared web credentials when you can’t find the login credentials in the keychain.
To read the user’s credentials from the shared web credentials, use the SecRequestSharedWebCredential(_:_:_:) function as shown in Listing 3.
Accessing shared web credentials
SecRequestSharedWebCredential(NULL, NULL, ^(CFArrayRef credentials, CFErrorRef error) {
if (error != NULL) {
// If an error occurs, handle the error here.
[self handleError:error];
return;
}
BOOL success = NO;
CFStringRef server = NULL;
CFStringRef userName = NULL;
CFStringRef password = NULL;
// If credentials are found, use them.
if (CFArrayGetCount(credentials) > 0) {
// There will only ever be one credential dictionary
CFDictionaryRef credentialDict =
CFArrayGetValueAtIndex(credentials, 0);
server = CFDictionaryGetValue(credentialDict, kSecAttrServer);
userName = CFDictionaryGetValue(credentialDict, kSecAttrAccount);
password = CFDictionaryGetValue(credentialDict, kSecSharedPassword);
// Attempt to log in
success = [self logIntoServer:server user:userName password:password];
}
if (!success) {
[self promptForUserNameAndPassword];
} else {
[self saveCredentialsToKeychainForServer: server user:userName password:password];
}
});
Note
The keychain supports saving and loading a wide range of possible credential types. These types can be user name and password pairs, authentication tokens or cookies. Shared web credentials, however, are much more restrictive. You can save only user name and password pairs to the shared web credentials.
Creating a User Account in the App
If the user can create new accounts in your app, you should save the user name and password to the shared web credentials. In this way, the user can easily access the account from Safari, as well as from within your app. You can save the user’s name and password to the shared web credentials using the SecAddSharedWebCredential(_:_:_:_:) function as shown.
Creating a user account
SecAddSharedWebCredential(domain, name, password, ^(CFErrorRef error) {
if (error != NULL) {
// Handle the error here...
return;
}
// The credentials have been successfully saved.
});
If there are no existing credentials for this user name and domain, this method completes without prompting the user for permission.
Changing a User’s Password
If the user changes her password in the app, you must update both the credentials stored in the keychain and in the shared web credentials. You can change a password using the SecAddSharedWebCredential(_:_:_:_:) function. This is exactly the same procedure used when creating a new user account (see Listing 4). However, if credentials already exist for the given user name and domain, this method prompts the user for permission before making the change. The user can cancel this change.
Deleting a User’s Account
If the user deletes her account, you should remove the credentials from both the keychain and the shared web credentials. You can remove the credentials for a given domain and user name by calling the SecAddSharedWebCredential(_:_:_:_:) function and passing NULL for the password.
Deleting a user account
SecAddSharedWebCredential(domain, name, NULL, ^(CFErrorRef error) {
if (error != NULL) {
// Handle the error here...
return;
}
// The account information has been successfully deleted.
});
The system prompts the user for permission before deleting their user name and password from the shared web credentials. Users can cancel this change.
Note
Use SecAddSharedWebCredential(_:_:_:_:) to remove a user’s credentials only when the user deletes her account. Do not use this method when the user simply logs out. Passing a NULL password to SecAddSharedWebCredential(_:_:_:_:) removes the user’s credentials and prevents Safari from autocompleting her login information.