Sending an Authentication Message

The Messages for Business authentication feature allows a user service agent or a bot to send an authorization access request to a user for specific information.

This request displays as a bubble on the device with a Sign In call to action. The user then signs into the authentication service with their username and password. Financial services, insurance, and e-commerce use this feature to ensure that users authorize access to their private data in a way that is not visible to either the user service provider or Apple Messages for Business servers.

You can use a third-party service as the authentication service, password autofill, or you can use an authentication endpoint that you already control. For more information, see Authentication Message.

Audience

The Messages for Business authentication feature relies on advanced cryptography. We wrote this section for an audience with sufficient background in cryptographic concepts to implement the standards described.

For a better understanding about the field of cryptography, see the following:

For a better understanding of authentication and authorization technologies:

  • OAuth 2 in Action by Justin Richer Antonio Sanso, ISBN: 9781617293276, 2017
  • OAuth 2.0 is the industry-standard protocol for authorization

For more information on the specific standards used by Messages for Business:

Rationale

We chose elliptic-curve cryptography (ECC) and a large key size for strong encipherment by current technology. This also anticipates future development of security technology.

The OAuth2 specification, of course, is an industry standard for authorization. We chose two flows from this specification to ensure flexibility. The private/public key pairs can be generated either by the MSP or the brand for either flow.

The key derivation function specification ensures that the public key can be communicated through a text field in an unambigous way.

Proceed to the Exercises

To learn how to pass authentication information using the /authenticate endpoint, complete the following exercises:

  1. Exercise: Sending an Authentication Request.
  2. Exercise: Receive and Parse an Authentication Response.
  3. Exercise: Decode the Auth Token and Retrieve User Data.

Exercise: Sending an Authentication Request

This exercise uses a third-party service, LinkedIn's OAuth2 API, to authenticate.

To make your chosen OAuth2 provider available, you need to request a security audit for your Apple Business Apple Business Register account. The approval process can take 2-3 business days.

Most third-party authentication service providers ask you to create an app on their platform. Some platforms simply refer to it as setting up a client, which is the name given under the OAuth2 specification, and some refer to it as an OAuth2 service.

For each service used, you have to tell the service where to send requests. This is called the redirect_uri or callback URL. Always enter https://auth.businesschat.apple.com into the field.

Prior to sending authentication requests, you need to retrieve the following fields from each third-party service and enter these into Apple Business Register:

  • Response type, either code or token [*]
  • OAuth URL
  • Token URL, for the token process; if you use the Implicit flow, leave this URL blank
  • Client identifier
  • Client secret
  • Scope
  • Decrypted token endpoint URL

NOTE The the OAuth2 specification covers the response type code that corresponds to the Authorization Code grant type, and response type token that corresponds to the Implicit grant type. These designations can lead to confusion since the token response type requires the Token URL in Apple Business Register to be blank. The authorization server provides the token directly (implicitly) so it doesn't have to be retrieved by the Token URL.

The response type, OAuth URL, and token URL are from the API documentation of the authentication service provider. The client identifier and client secret are generated for you within their API account webpage.

The scope and decrypted token endpoint URLs go together, with some authentication providers offering different types of access to information. Check the API documentation for the details of which strings to use for these fields.

Step 1: Set up an Authentication Endpoint

In this exercise, you set up an authentication service and add information about the service into Apple Business Register. There is no code to run for this task.

To follow along with these exercises, you'll need a LinkedIn developer and user account for testing.

  1. Log into LinkedIn Developer and click Create App from their API site.

  2. Enter the appropriate information into the app profile on the site. Where you see Redirect URL, enter: https://auth.businesschat.apple.com

  3. Retrieve the Client Identifier and Client Secret. These are string fields that are unique to your application, and required by Apple Business Register for the LinkedIn endpoint to serve as your authentication service.

  4. Go to your existing Messages for Business account in Apple Business Register (https://register.apple.com), find the End User Authentication section, and enter the following values:

    • OAuthURL: https://www.linkedin.com/oauth/v2/authorization
    • Token URL: https://www.linkedin.com/oauth/v2/accessToken
    • Client Identifier: Use the unique identifier from the LinkedIn API
  5. Make sure you click Submit at the bottom of the account page. Changes on Apple Business Register become active after you submit the profile and Apple approves it. The security audit for your authentication service takes 2-3 business days. You need to allow sufficient time in your development schedule for this approval.

  6. To ensure prompt approval, send an email reminder about the authentication audit to messagesforbusiness-support@apple.com. Include the Business ID or a link to the URL in Apple Business Register.

Step 2: Generate Public/Private Key Pair and Nonce

This task demonstrates how to produce a unique nonce and a private/public key pair for use in the authentication request payload.

Complete this task by running the code in Listing 17_generate_key_pair_and_nonce.py below and observe that the nonce and public/private key pairs are unique.

The nonce is a short string that is unique to each transaction. It does not have to be cryptographically secure to be compliant. It is a unique value for each request to ensure that a man-in-the-middle cannot perform a replay attack on the authentication provider's endpoint. To learn more about the reason for needing a unique nonce on each request, see https://auth0.com/docs/protocols/oauth2/oauth-state.

The code example below generates a random 32-character string. We could use a hash of the date and time, a sequential progression, or even a different length of string. The length of the string is explicitly left out of the specification, see https://tools.ietf.org/html/rfc6749#section-4.1.2

The key pair is formed by a cryptographically secure library. We use the hazmats methods of the Python cryptography library for the code samples. For Java, you can use BouncyCastle. Other language and platform combinations require a different library.

NOTE You must generate a unique public/private key pair for each authentication request. Reusing the key pair would produce an unnecessary security threat surface. It is a requirement of our platform to generate unique pairs for each authentication request in a production environment.

Use a well-tested and validated library. Many published open-source libraries may not be the best library for your platform. You can also write your own unit tests to ensure the library is compliant with the cryptography standards and security best practices that you want to build into your product.

Perform the following tasks on your test server:

  1. Locate the code zip folder and unzip it.
  2. Locate and run the 17_generate_key_pair_and_nonce.py file.

Expected MSP server response

Ready to generate authentication request with parameters
request_id: 25d96 <truncated>
responseEncryptionKey: BP/Cc <truncated>
nonce (aka state): L+C55 <truncated>
private key, base64: Mxhdr <truncated>

Step 3: Send the Authentication request

In this exercise, you send an authentication request to the user's device.

The authentication request displays as a login bubble on the device. When the user clicks the bubble, a LinkedIn login drawer appears and the user enters their LinkedIn username and password. After submitting the credentials, the login drawer disappears and displays the authentication result.

Your MSP platform sends the authentication request to a distinct authentication endpoint, specifically https://mspgw.push.apple.com/v1/authenticate. After a successful authentication, your MSP platform continues receiving non-authentication traffic on your /message endpoint.

Perform the following tasks on your test server:

The Python code is split into two files: auth_util.py and 18_send_auth_request.py. The first file, auth_util.py , is a library of handlers used for the authentication section exercises. The second file, 18_send_auth_request.py, calls the functions in auth_util.py file and sends the authentication request to the user's device.

  1. Locate and edit the 18_send_auth_request.py file by inserting the destination_id, located towards the bottom of the file, with the source_id from the output in Exercise: Receiving a Text Message.
  2. Save and run the 18_send_auth_request.py file and ensure that the import can successfully reference the auth_util.py file.

Expected MSP server response

Save private key for use later, base 64: n9oMl <truncated>
 * Running on http://0.0.0.0:8002/ (Press CTRL+C to quit)
Messages for Business server return code: 200
Send authentication request with parameters

request_id: 8c202 <truncated>
responseEncryptionKey: BGbqf <truncated>
nonce (aka state): LyZzh <truncated>
private key, base64: n9oMl <truncated>

Exercise: Receive and Parse an Authentication Response

In this exercise, we receive an interactive message response at our messaging endpoint with either a successful login or an unsuccessful login prompted by the authentication request.

The authentication request conforms to the interactive message class, even though it's delivered to its own endpoint. The response arrives at your MSPs /message endpoint. It conforms to the interactive message response, similar to the list picker response, with a few unique fields for authentication.

When developing your Messages for Business integration, you need to parse interactive message responses into the different types to ensure that each can be routed to the correct handler. For this exercise, we show a way of parsing the response to filter out the authentication response from other interactive message response types.

Perform the following tasks on your test server:

  1. Locate and run the 19_receive_auth_response.py file in background mode from the command line.
  2. Ensure the library auth_util.py is available to the 18_send_auth_request.py code.
  3. Run the code from 18_send_auth_request.py to generate the authentication request.
  4. On the device, log in to LinkedIn.
  5. On the console, observe the payload received by your MSP platform.

Expected MSP server response

Make a note of the encrypted token displayed in the output, this piece is used in the next exercise.

NOTE For easier understanding, the u has been removed from the MSP server response below.

payload
  {
   'interactiveData': {
      'sessionIdentifier': 'f73dd <truncated>',
      'bid': 'com.apple.messages. <truncated>',
      'data': {
         'receivedMessage': {
           'style': 'icon',
           'title': 'Sign In to LinkedIn’
           },
         'authenticate': {
           'status': 'authenticated',
           'token': 'BJuPw <truncated>'
           },
         'replyMessage': {
           'style': 'icon',
           'alternateTitle': 'You Signed In',
           'title': 'You Signed In’
           },
         'version': '1.0',
         'requestIdentifier': '8c202 <truncated>'
         }
       },
     'sourceId': 'urn:mbid:AQAAY <truncated>',
     'destinationId': '...<removed>...',
     'v': 1,
     'type': 'interactive',
     'id': 'e7ba2 <truncated>'
     }
   interactive_data: {
     'sessionIdentifier': 'f73dd <truncated>',
     'bid': 'com.apple.messages. <truncated>',
     'data': {
       'receivedMessage': {
       'style': 'icon',
       'title': 'Sign In to LinkedIn’
       },
     'authenticate': {
       'status': 'authenticated',
       'token': 'BJuPw <truncated>'
       },
     'replyMessage': {
       'style': 'icon',
       'alternateTitle': 'You Signed In',
       'title': 'You Signed In’
       },
     'version': u'1.0',
     'requestIdentifier': '8c202 <truncated>'
     }
  }
request_id: 8c202 <truncated>
status: authenticated
encrypted_token: BJuPw <truncated> #Used in Exercise: Decode the Auth Token and Retrieve User Data
Our work is done for this routine.

Exercise: Decode the Auth Token and Retrieve User Data

This exercise decrypts the auth token and uses it to request the user information from the authentication provider.

In your full implementation, this exercise requires you to copy and paste values delivered through a database or encrypted cloud storage. The result is a print out of the LinkedIn headline and personal information for the user who successfully authenticates.

Perform the following tasks on your test server:

  1. Locate and run the 19_receive_auth_response.py file in the background.
  2. Run the 18_send_auth_request.py file and note the public and private key Base64-encodings.
  3. When the authentication response is returned, the 19_receive_auth_response.py code returns and prints the encrypted authentication token. TheBase64-encoded string is notably longer than the other strings.
  4. Quickly copy and paste these three strings into the 20_decode_token_get_user_data.py file in the appropriate designated string fields. You have to work quickly since the encrypted token has an expiration—usually measured in minutes.
  5. Save and run the 20_decode_token_get_user_data.py file. It outputs the LinkedIn headline, full name, and email address for the user who authorized the information.

We use a 30 second timeout parameter here, rather than 10 seconds. There is more latency in this process, so we may need to wait longer for it to complete.

Other third-party services can be similarly provisioned with the appropriate endpoint for using the decrypted auth token.

Expected MSP server response

You will see the user's headline and name in the payload retrieved from LinkedIn.

token (decrypted): AQUqY <truncated>
{
 'headline': 'Engineering Program Manager in Silicon Valley’,
 'lastName': 'Chen',
 'siteStandardProfileRequest': {
   'url': 'https://www.linkedin.com/profile/view?<truncated>&authType=name&authToken=_VXR&trk=api*a5144733*s5062023*'
   },
 'id': '3FC <truncated>',
 'firstName': 'Mei'
}

Using Auth0 as an Alternative to LinkedIn

We chose LinkedIn for the example because their dashboard was simple and easy to follow. Auth0 is a more powerful system, though. It has more features and better coverage of the OAuth2 specification.

You can navigate to https://auth0.com and sign up for a free account.

From your Auth0 management account:

  1. Create Application > Regular Web Application.
  2. Under Allowed Callback URLs, add https://auth.businesschat.apple.com. Ensure that the other URL fields (including Login URI, Logout URLs, Web Origins) are be left blank.
  3. Refresh Token Behavior by selecting Non-Rotating.
  4. Select Advanced Settings > Grant Types. Based on the process you want to use, select "Code Authorization" or "Implicit".
  5. You have to add users onto an allow list in Auth0 similar to the allow list in Apple Business Register. Add your test users with Users & Roles > + Create User. You can also enable providers, such as Google, to allow any user with an account on that system.