Authentication Message - ** DEPRECATED **
Note
A new, upgraded Authentication message type is now available in iOS 16 and macOS 13. Be sure to review it in New Authentication Message Specification. All MSPs are required to support this new type beginning Fall 2022.
Pass a customer's authentication data to a business by using the OAuth protocol. Messages for Business allows authentication data to pass between customers and businesses on the Messaging
Service Provider (MSP) using the authenticate
endpoint as described in Sending an Authentication Message.
After the user is authorized, the system sends an OAuth response and the user’s device receives a login form. The user enters their username and password in the login form to continue the authorization process.
Sending an Authentication Message
Pass authentication data between the business or Customer Service Platform and the customer's device using OAuth.
URL
POST https://mspgw.push.apple.com/v1/authenticate
HTTP Headers
For more information, see the HTTP Headers in Common Specifications.
HTTP Body
In iOS 15, Apple enhanced the authentication method built into Messages for Business. Prior to iOS 15, the authorization code and parameters appeared in the URI request.
Pre-iOS 15 example: server.example.com/?grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
Starting in iOS 15, the authorization code and parameters appear in the HTTP entity-body according to the standard for OAuth 2.0.
Name | Description |
---|---|
AuthenticateRequestBody |
Content-Type: application/json |
Response Codes
You can find the list of Response Codes in Common Specifications.
Businesses must supply authentication details about the OAuth provider, including authentication endpoint URLs, client identifier, and business information verified by Apple Business Register. Changing any of these authentication parameters requires additional verification and approval from multiple customers that own or administer the business.
Pass Authenticate Data
Passing authenticate data requires sending a POST
request to the /v1/authenticate
endpoint
hosted by Messages for Business with the authenticate message in the request body. You must secure
the authenticate endpoint before sending a request from a business to the customer. When
the OAuth request is sent to the provider, the endpoints must present a valid Extended
Validation (EV) certificate for a successful authorization.
You use the AuthenticateRequestBody.Authenticate
dictionary key and the responseEncryptionKey
to authenticate with the OAuth provider
endpoints. This workflow enables the OAuth provider to audit the public key used to encrypt
the authentication token. Use the requestIdentifier
in the data dictionary to identify
the authentication request and map the OAuth token in the response to the request originator.
Either the business or the MSP generates the requestIdentifier
and responseEncryptionKey
.
Messages for Business returns a JSON dictionary containing the encrypted token field. The business or CSP can decrypt the access token and verify the user's access. If the business is responsible for decrypting the access token, the business and MSP must implement the delegation of key generation and token verification. The tall, rectangular boxes on the vertical lines in the figure below denotes key generation and access token verification.
Validate the Public Key
Messages for Business authentication uses OAuth to provide a way for the authentication provider and the business to audit the public key sent in a user's authentication request. The audit detects when a public key has been tampered with or replaced, which could result in the customer's authentication token leaking to an unintended party.
When a user's device makes the HTTPS call to the authorization endpoint, it includes two
additional request parameters in addition to the standard authentication request: responseEncryptionKey
and userHandle
. The authentication provider can make an API call to the business with
the responseEncryptionKey
and the user's opaque ID.
If the business is acting as its own authentication provider, it checks these values against its internal database. If the business made a request with that customer's key, the authentication provider proceeds by sending back the code or access token. If the customer's key does not match the parameter values in its pending requests, the customer's key may have been tampered with and the authentication provider must immediately fail the request from the device.
Note
You can also work with your authentication provider on proper validation of the public key.
Compose an Authentication Request
The authenticate request is an interactive message. When composing an authenticate request,
include the AuthenticateRequestBody.Authenticate
dictionary key in the BaseInteractiveMessage
dictionary to describe the behavior and content of the authentication request.
You can send authentication data to a customer’s device with the auth capability announced,
which is included in the capability-list
header of the message request. Devices that
support authenticate
messages have iOS 12 or later and macOS 10.14.0 or later. For more information
about the Authorization
header field, see Authorizing Messages.
Successful Authentication
Example of an authentication request. Note that the clientSecret
key is forwarded to the
authentication provider as client_secret
.
Request
{
"type": "interactive",
"interactiveData": {
"bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",
"data": {
"version": "1.0",
"requestIdentifier": "3EF748B5-<truncated>",
"authenticate": {
"oauth2": {
"responseType": "code",
"scope": ["email", "profile"],
"state": "security_token",
"responseEncryptionKey": "BFz948MTG3OQ0Q69 <truncated>",
"clientSecret": "client_secret"
}
},
"images": [{
"data": "iVBORw0KGgoAAAANSUhEUgAA <truncated>",
"identifier": "1"
}]
},
"receivedMessage": {
"title": "Sign In",
"imageIdentifier": "1"
},
"replyMessage": {
"title": "You Signed In",
"imageIdentifier": "1"
}
}
}
Response
{
"data": {
"version": "1.0",
"requestIdentifier": "8EF748B5-<truncated>",
"authenticate": {
"status":"authenticated",
"token": "<An encrypted Base64-encoded token.>"
},
"images": [{
"data": "iVBORw0KGgoAAAANSUhEUgAAADIA <truncated>",
"identifier": "1"
}]
},
"bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",
"receivedMessage": {
"title": "Sign In",
"subtitle": "Authentication required to access your customer data",
"style": "icon",
"imageIdentifier": "1"
},
"replyMessage": {
"title": "You Signed In",
"subtitle": "",
"style": "icon",
"imageIdentifier": "1"
}
}
Failed Authentication
Request
{
"type": "interactive",
"interactiveData": {
"bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",
"data": {
"version": "1.0",
"requestIdentifier": "3EF748B5-<truncated>",
"authenticate": {
"oauth2": {
"responseType": "code",
"scope": ["email", "profile"],
"state": "security_token",
"responseEncryptionKey": "BFz948MTG3OQ0Q69JHUiBG7 <truncated>",
"clientSecret": "client_secret"
}
},
"images": [{
"data": "iVBORw0KGgoAAAANSUhEUgA <truncated>",
"identifier": "1"
}]
},
"receivedMessage": {
"title": "Sign In",
"imageIdentifier": "1"
}
}
}
Response
{
"data": {
"version": "1.0",
"requestIdentifier": "8EF748B5-<truncated>",
"authenticate": {
"status": "failed",
"errors": [{
"code": 2,
"domain": "com.apple.icloud.messages.business.cryptor",
"message": "Key is not UTF8"
}]
},
"images": [{
"data": "iVBORw0KGgoAAAANSUhEUgAA <truncated>",
"identifier": "1"
}]
},
"bid": "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.icloud.apps.messages.business.extension",
"receivedMessage": {
"title": "Sign In",
"subtitle": "Authentication required to access your customer data",
"style": "icon",
"imageIdentifier": "1"
},
"replyMessage": {
"title": "Authentication Failed",
"subtitle": "",
"style": "icon",
"imageIdentifier": "1"
}
}
AuthenticateRequestBody Dictionary
InteractiveMessageData dictionary with the authenticate key added used in sending an authentication message.
Properties
Name | Type | Description |
---|---|---|
authenticate |
object | REQUIRED. A dictionary that describes the authentication request. |
images |
array | REQUIRED. An array of image dictionaries |
requestIdentifier |
string | REQUIRED. An identifier for the authenticate request. |
version |
string | REQUIRED. A numerical version number of the message extension schema. |
AuthenticateRequestBody.Authenticate Dictionary
Keys for the Authenticate Data dictionary used in sending an authentication message.
Properties
Name | Type | Description |
---|---|---|
oauth2 |
object | REQUIRED. A dictionary that describes the authentication request. |
AuthenticateRequestBody.Authenticate.Oauth2 Dictionary
Keys for the OAuth2 Data dictionary used in sending an authentication message.
Properties
Name | Type | Description |
---|---|---|
clientSecret |
string | REQUIRED. A string indicating the secret provisioned by the authorization server. |
responseEncryptionKey |
byte | REQUIRED. A string indicating the Base64-encoded public key that encrypts the access token returned in the response. |
responseType |
string | REQUIRED. A string indicating the type of authentication request. |
scope |
array | REQUIRED. An array of scope items that specifies the scope of the request.This dictionary entry gives the exact fields of data that the authentication service provides to the client requesting the authentication. |
state |
string | REQUIRED. A string indicating the state of the authentication request. |
AuthenticateRequestBody.Authenticate.Oauth2.Scope Dictionary
An array of short text fields that describes the granted access for read and write. This dictionary entry gives the exact fields of data that the authentication service provides to the client requesting the authentication.
object AuthenticateRequestBody.Authenticate.Oauth2.Scope
Authenticate Webhook Event
Webhook Payload
Keys used in the JSON dictionary which is the response body.
Name | Type | Description |
---|---|---|
errors |
object | A list of errors for authentication failure cases. See Error Codes. |
status |
string | A string indicating the status of the authentication request. |
token |
string | A Base64-encoded authentication token string, which is encrypted with the responseEncryptionKey from the request when authentication is successful. |
Errors
Name | Type | Description |
---|---|---|
code |
integer | A numerical error code. See Error Codes. |
domain |
string | A string indicating the error domain. |
message |
string | A string indicating the description of the error. |
Decrypting the Authentication Token
To authenticate users, you need to decrypt their encrypted authentication token from the response. The authentication token should include the following:
- A 384-bit elliptic curve secp384r1 public key specified in the authenticate request.
- An encrypted authentication token, for use by the Messaging Service Provider (MSP) platform.
You can create the token on the customer's device using the
eciesEncryptionCofactorVariableIVX963SHA256AESGCM
algorithm.
The business or MSP platform uses the associated private key generated for the request to decrypt and obtain the clear text authentication token.
For more information on authentication, see Sending an Authentication Message.
About the Authentication Token
When a customer successfully completes authenticating with a business, the MSP platform receives an authentication token. This token includes encrypted information and requires a decryption procedure to retrieve the information to determine the authenticity of the customer.
The authentication token is a Base64-encoded string contained in the JSON payload returned by the interactive message from the Messages for Business server. You can find it nested in the interactiveData/data/authenticate/token folder.
The authentication token uses the Elliptic Curve Integrated Encryption Scheme (ECIES). There are several versions for ECIES and keys, and encrypted data are not always compatible between versions. Some applications use a derivative or a subset of a version, so they may not be compatible with other implementations.
Messages for Business uses the secp384r1
curve for generating public/private key pairs, and X9.63
for encoding the public keys. Libraries compatible with these standards are available across
many languages and platforms.
Before developing the production code for your implementation, you should understand the concepts of encryption and be familiar with the libraries to handle these items on your platform. Some libraries have an abstract cryptographic library that requires deep understanding to apply the correct algorithm and parameters. Other libraries implement many methods and are fairly straightforward to use, but require a great deal of research to determine a suitable method for a particular application. Understand these concepts before you begin your production code.
You should validate the compatibility of your particular implementation with the standards by building a comprehensive test. You should also review your implementation with information security experts. It is recommended to perform a security review with an independent security team before deployment.
Decrypt the Authentication Token
In this decryption exercise, you use a Base64-encoded binary data and an X9.63-encoded uncompressed public key. The unsigned scalar private key example has been converted to bytes. The private key is not sent in the request, so businesses can choose any encoding format.
Use the following values so that you can follow along with the exercises. You can use the immediate mode on your favorite language or write sample code on your platform.
Public Key
BNY+I93aHVkXnNWKVLdrMJLXpQ1BsyHYoiv6UNi4rDUsRx3sNNhW8FNy9yUwxYprAwwfj1ZkoJ61Fs+SwjIbGPtXi52arvSbPglyBN4uAxtP3VP3LCP4JtSEjdgsgsretA==
Private Key
pX/BvdXXUdpC79mW/jWi10Z6PJb5SBY2+aqkR/qYOjqgakKsqZFKnl0kz10Ve+BP
Encrypted Authentication Token
BDiRKNnPiPUb5oala31nkmCaXMB0iyWy3Q93p6fN7vPxEQSUlFVsInkJzPBBqmW1FUIY1KBA3BQb3W3Qv4akZ8kblqbmvupE/EJzPKbROZFBNvxpvVOHHgO2qadmHAjHSmnxUuxrpKxopWnOgyhzUx+mBUTao0pcEgqZFw0Y/qZIJPf1KusCMlz5TAhpjsw=
To decrypt the authentication token, use the following steps:
- Extract the ephemeral public key from the encrypted data.
- Derive the public numbers from the ephemeral public key.
- Obtain a shared key using an Elliptic Curve Cyrptopgraphy Cofactor Diffie-Hellman (ECC CDH).
- Generate the derived key and initial vector by running the shared key through the X9.63 Key Derivation Function with SHA256 hash function.
- Perform an AES-GCM decryption using the encrypted data string and initialization vector (IV) obtained in step 4.
The following sections take you through the process of decrypting the authentication token, as detailed in the previous steps.
Extract and Confirm the Ephemeral Public Key
Extract the ephemeral public key from the encrypted data. The authentication token contains several parts:
- Byte 0 is 0x04 and indicates an uncompressed key form.
- Bytes 0...96 are the ephemeral public key. Note that 0-byte is part of the ephemeral public key in addition to indicating the uncompressed form.
- Bytes 97...n-16 are the encrypted data, where n is the length of the authentication token.
- Bytes n-15...n-1 are the encryption tag.
When you compute the key on the secp384r1 curve, the key data is 96 bytes (384/8 * 2). The x and y coordinates can have up to 384-bytes.
Exercise
First, Base64-decode the authentication token string. This results in a 142-byte binary which is the actual authentication token. The first byte, 0x04, indicates the key in an uncompressed form.
Use the Base64 library and binary object manipulation library for your language and platform. Base64-encode the ephemeral public key from the binary form. The following uncompressed ephemeral key should result:
BDiRKNnPiPUb5oala31nkmCaXMB0iyWy3Q93p6fN7vPxEQSUlFVsInkJzPBBqmW1FUIY1KBA3BQb3W3Qv4akZ8kblqbmvupE/EJzPKbROZFBNvxpvVOHHgO2qadmHAjHSg==
Derive the binary for the encrypted data portion and Base64-encode it. The resulting encrypted data string is:
afFS7GukrGilac6DKHNTH6YFRNqjSlwSCpkXDRj+
The Base64-encoded encryption tag is:
pkgk9/Uq6wIyXPlMCGmOzA==
Save the encrypted data string and tag as these are used in Perform an AES-GCM Decryption.
Derive the Public Numbers
Derive the public numbers from the public key. The public numbers are the x and y coordinates of the elliptic curve used in the encryption process. Use a method within the cryptographic library on your platform to derive these values.
Some libraries pass the secp384r1 curve to the routine as a parameter along with the public key. Other libraries have a method for the secp384r1 that accepts the public key as a parameter. Familiarize yourself with the cryptographic library and apply the best method to this step.
Exercise
Pass the secp384r1 curve and the ephemeral public key into your cryptography library method for deriving the public numbers.
Continuing from the values in the previous section, you should receive the following two coordinates:
x=8706462696031173094919866327685737145866436939551712382591956952075131891462487598200779332295613073905587629438229
y=10173258529327482491525749925661342501140613951412040971418641469645769857676705559747557238888921287857458976966474
Obtain the Shared Key Using the ECC CDH
To obtain the shared key, perform an ECC CDH operation using the ephemeral public key and the private key. You should get the following shared key after using the ECC CDH operation:
2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif
Generate the Derived Key and Initial Vector
Run the shared key through the X9.63 Key Derivation Function with SHA256 hash function. This results in a 48-byte payload.
Use the initialization vector to perform the decryption in Perform an AES-GCM Decryption.
The first 32-bytes yields the derived key, for this exercise:
mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
The last 16-bytes serve as the IV:
rV3qrszd0PMPgeRhNnlOYA==
Perform an AES-GCM Decryption
Refer back to the saved values from the first step, Extract and Confirm the Ephemeral Public Key. Use the following encrypted data string:
afFS7GukrGilac6DKHNTH6YFRNqjSlwSCpkXDRj+
and the IV from Generate the Derived Key and Initial Vector:
rV3qrszd0PMPgeRhNnlOYA==
to perform a message authentication code (MAC) validation, include the encryption tag from Extract and Confirm the Ephemeral Public Key:
pkgk9/Uq6wIyXPlMCGmOzA==
This yields a plain text string token that you can use for authentication:
xXTi32iZwrQ6O8Sy6r1isKwF6Ff1Py
Troubleshooting
Decryption fails if the keys or associated tag derived in Generate the Derived Key and Initial Vector are incorrect. Failed decryptions result in rejected tokens, including the associated tag validation.
Using Password AutoFill to Authenticate Users
Provide customers with an easy solution to perfom authentication on their iOS devices.
Supporting the Password AutoFill feature requires that the authorization input element must annotate the autocomplete HTML attribute in the following format:
<input autocomplete="value">
Possible values for the autocomplete attribute are username, current-password, new-password, and one-time code. For more information about these values, see Enabling Password AutoFill on an HTML Input Element.
Note
Password AutoFill is supported in Safari 12 for iOS 12 and later and Safari 12 for macOS 10.14 and later.
After the customer has been authorized, the system sends an OAuth response. In this step, the customer’s device is redirected to a URL that triggers a login form using an existing third party login system. For more information, see Password AutoFill.
Error Codes
Possible errors thrown by the customer's device.
The device may return various errors as listed in the following tables. All errors in the
tables are from the com.apple.icloud.messages.business
domain.
Table 1 Authentication domain errors
Error | Code | Message | Description |
---|---|---|---|
BCTokenMissingError |
1 | Missing Token or Missing Code. | Thrown when the authentication plugin cannot retrieve a token or a code from the redirect URL. |
BCEmptyDataReceivedError |
2 | Empty data received when exchanging token. | Thrown when the authentication plugin receives an empty response when exchanging the code for a token. |
BCAccessTokenMissingFromResponseError |
3 | Missing access token from response. | Thrown when the authentication plugin receives a valid response, but the response is missing access_token from the JSON body. |
Table 2 Cryptor domain errors
Error | Code | Message | Description |
---|---|---|---|
BCPublicKeyIsEmptyError |
1 | Empty string received for key. | Thrown when the cryptor is given an empty public key. |
BCPublicKeyIsNotUTF8Error |
2 | Key is not UTF-8. | Thrown when the cryptor Base64-decodes the public key and fails because the encoding is not UTF-8. |
BCPublicKeyIsInvalidError |
3 | Public key is invalid. | Thrown when the cryptor fails to validate the key against SecKeyAlgorith.eciesEnCryptionCofactorVariableVX963SHA256AESGCM. |
BCPublicKeyInternalError |
3 | Failed adding key.Failed reading key.Failed deleting key. | Thrown when the cryptor cannot complete the given task due to an internal error. |
BCEncryptionError |
4 | Unable to encrypt token. | Thrown when the cryptor fails to encrypt a given payload using the provided public key. |
Tutorial Exercise
For more help or guidance, see our Tutorial: Exercise: Sending an Authentication Message.