Implementing Authentication

Starting an implementation using browser authentication

Implementing browser authentication involves the following key steps:

  1. Respond to getAppLink to establish the household with your service 
    Sonos calls getAppLink to send information about the household to your service. Your service returns information that enables the user to authenticate with your service.
  2. Respond to getDeviceAuthToken to associate the user with the household 
    Sonos calls getDeviceAuthToken to acquire a token from your service. Your service establishes the token to represent the association between the authenticated user and the Sonos household. Sonos and your service then ensure authentication by exchanging the token.

Between the getAppLink and getDeviceAuthToken calls, the user authenticates with your service by using either your app or a browser to enter login credentials. Before we get into the detail processing, we'll describe the terms link code, authorization token, and private key.

Link codes provide authorization

Your service generates link codes and passes them back to Sonos in getAppLink responses. 

Authorization tokens tie a user to a household

An authorization token represents a specific user-household combination. Your service generates authorization tokens and passes them back in getDeviceAuthToken responses. 

Your application can use the following types of tokens:

  • non-expiring authentication - This token does not expire. Once a user logs in and authenticates during account setup, they never need to authenticate again. A token is generated representing the user and household to identify the user in other API calls, but the token does not contain names or passwords. 
  • expiring authentication with automatic refresh - Once a user logs in and authenticates during account setup, they never need to authenticate again. However, behind the scenes the user’s authentication is automatically refreshed by the system periodically. A token representing the user and household but not containing names or passwords is generated each time and used to identify the user in other API calls until it expires and a new token is requested.
  • expiring authentication - When a user authenticates, a specific time limit is set for how long they can remain logged in without manually logging in and authenticating again. A token representing the user and household but not containing names or passwords is generated each time the user logs in and used to identify the user in other API calls until it expires.

Private keys enable tokens to refresh

A private key is an ID associated with a specific authorization token that allows the token to be refreshed. If you decide to have your authorization tokens expire, you have the choice of requiring the user to log in again once the token expires or to support automatic refresh tokens. If you decide to implement refresh tokens, your service generates new tokens and private keys and passes them back to Sonos in getDeviceAuthToken responses. Details are covered in the section on Refreshing Authorization Tokens in Processing authentication credentials for API requests.

Respond to getAppLink to establish the household with your service

The getAppLink call is the first call in the authentication process. It sends the household ID and other information to your music service. The household ID identifies the user's Sonos system. To support multiple accounts, Sonos seeds the household ID to function as a unique ID for each account. The first account uses the household ID, while subsequent accounts have extra information appended.

The following images are examples of the Sonos app screens for the user to add a service to Sonos:

The following process flow shows the case where the user already has an account with your service and you are supplying a browser Web page from which the user will authenticate. 

  1. The user selects "Add Account". 
  2. The Sonos app sends a getAppLink request to your service. The <householdId> identifies the user's Sonos system. This first example uses only the <householdId> parameter. We'll discuss the other parameters later in Implementing app authentication.
  3. Your service provides an ID from your strings file in <appUrlStringId>. The ID identifies the string label for the button the user selects for launching the Web page. (See also Strings and localization.)
  4. Obtain the link code from your authorization service. 
    Sonos passes the link code back to your service later with getDeviceAuthToken when it requests authorization tokens. 
  5. Your service provides the Web page URL in <regUrl> and encodes the link code as a parameter of the URL.
  6. Return results for getAppLink are shown below. 

A getAppLink request from the Sonos app might look like this:

CONNECTION: close
ACCEPT-ENCODING: gzip
HOST: smapi.acme.com
USER-AGENT: Linux UPnP/1.0 Sonos/31.3-20100 (ICRU_iPhone3,1); iOS/Version 6.1.3 (Build 10B329)
CONTENT-LENGTH: 520
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "http://www.sonos.com/Services/1.1#getAppLink"
 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soapenv:Header>
      <ns:context>
      </ns:context>
      <ns:credentials>
      </ns:credentials>
   </soapenv:Header>
   <soapenv:Body>
      <ns:getAppLink>
         <ns:householdId>Sonos_ghsAflSonosakevCzmxcmFhN7pN</ns:householdId>
         <ns:hardware>iPhone8,2</ns:hardware>
         <ns:osVersion>Version 9.3.3 (Build 13G34)</ns:osVersion>
         <ns:sonosAppName>ICRU_iPhone8,2</ns:sonosAppName>
         <ns:callbackPath>sonos://x-callback-url/addAccount?state=sid%3D61703%26OAuthDeviceID%3DSonos_ghsAflSonosakevCzmxcmFhN7pN%26callbackPath%3D%2FaddAccount</ns:callbackPath>
      </ns:getAppLink>
   </soapenv:Body>
</soapenv:Envelope>

See getAppLink in the reference for descriptions of all parameters and return elements.

The simplest form of a getAppLink response is an <authorizeAccount> element containing the following minimum elements for a browser authentication response. 

  • <appUrlStringId> — An ID for the string that labels the button the user presses to launch the browser.
  • <deviceLink> — The authorization service needs to generate a unique link code for the user. For security purposes, we recommend giving the link code a short lifespan (1 hour or less) and do not reuse them. You are free to use any format you wish for link codes but there is a strict 32 character limit on length. Your service stores and associates the link code with the household ID. 
    • <regUrl> — The URL to your Web page where the user logs in to authenticate. 
    • <linkCode> — The generated link code from the authorization service, which represents this user's household in your music service. 
    • <showLinkCode> — A Boolean flag indicating whether the Sonos app should display the link code.
    • <linkDeviceId> — (Optional) A token, hidden from the user to prevent token phishing.

The <linkDeviceId> gives your service an extra, hidden, token to use to verify that the device you originally gave the token to is the same device sending you the request. The player does not share this with the user and sends it back in the getDeviceAuthToken request, which the player sends to your secure endpoint.

In most cases, you should encode the link code as a linkCode parameter in the <regUrl> and set <showLinkCode> to false. When the user opens the URL, your Web page can extract the link code. If you do not encode the link code in the <regUrl>, set <showLinkCode> to true. This causes the Sonos app to display the link code for the user so that they can later enter it on your authentication Web page.

Your service should send a response something like the following for browser authentication:

(HTTP headers omitted)
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <s:Body>
      <ns:getAppLinkResponse>
         <ns:getAppLinkResult xsi:type="appLinkResult" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ns:authorizeAccount>
               <ns:appUrlStringId>SIGN_IN</ns:appUrlStringId>
               <ns:deviceLink>
                  <ns:regUrl>https://oauth.acme.com/deviceLink/home?linkCode=AKVS3FHEAUCXAQKLkMA</ns:regUrl>
                  <ns:linkCode>AKVS3FHEAUCXAQKLkMA</ns:linkCode>
                  <ns:showLinkCode>false</ns:showLinkCode>
               </ns:deviceLink>
            </ns:authorizeAccount>
         </ns:getAppLinkResult>
      </ns:getAppLinkResponse>
   </s:Body>
</s:Envelope>

Respond to getDeviceAuthToken to associate the user with the household

The getDeviceAuthToken call sends the household ID and link code (from the getAppLink response) to your service to get the authorization token. Processing of getDeviceAuthToken depends on what results your service returns for getAppLink

  • App authentication - If your service returns an app URL in the <appUrl> element of getAppLink and the user has the app installed, processing uses app authentication.
  • Browser authentication - If your service does not return the <appUrl> element for getAppLink or the user does not have the app installed, the processing uses browser authentication with the URL from the <regUrl> element of getAppLink.

The following summarizes the differences between app authentication and browser authentication for getDeviceAuthToken processing:

For app authentication, after your app completes authentication and obtains user authorization, your app uses inter-app communication to call back and reestablish control to the Sonos app (shown in blue). Because a Web page cannot communicate back to the Sonos app after obtaining user authorization, the best your Web page can do is display to the user instructions to return to the Sonos app. 

The rest of this section describes the details of how to respond to getDeviceAuthToken for browser authentication. (The response for app authentication is covered  in Implementing app authentication.) Note that the user has to manually authenticate before the authorization service can establish the authorization token. Therefore, your service may not be ready to provide the authorization token when it receives the getDeviceAuthToken request. The Sonos app sends the call repeatedly, polling for the response until the call either succeeds or fails. Thus there are three possible responses your service needs to provide for getDeviceAuthToken requests: retry, success, or failure. 

The following process flow continues with the case where the user already has an account with your service and your service supplied a Web page from which the user authenticates. After getAppLink returns, the user chooses to add the account.

  1. The Sonos app sends a getDeviceAuthToken request to your service with the <householdId> and the <linkCode> parameters.
    The Sonos app will regularly poll with this request for up to seven minutes until it receives a success response from your service, which indicates the user's account is authenticated. Until then, your service continues to return a retry response.
  2. The Sonos app starts the Web browser, which presents the Web page (<regUrl>) to the user.
  3. The user enters their account credentials for your service and follows your authentication process in the browser.
  4. Your Web server obtains authorization from your authorization service.
  5. Your Web page tells the user to switch back to using the Sonos app.
  6. Your service gets the authorization token for this link code from your authorization service.
  7. Your service sets the following additional values:
    • A private key for managing refresh tokens.
    • A hash code value your service uses to identify this user.
    • An optional nickname from the user's account on your service so that the Sonos app can pre-populate the name on the user's system.
  8. Your service finally returns the success response for a getDeviceAuthToken request.
  9. The Sonos app communicates with a Sonos player, which first confirms the user account is not a duplicate, and then creates the account for the Sonos household. The Sonos household is then able to query your service with the link code to get the user-specific authorization token, which is then stored on the user's Sonos system as their authorization information. 
  10. Your service is added to the user's Sonos household.

Finally, the user sees a screen such as the following where they can change the nickname for their account.

A getDeviceAuthToken request from the Sonos app might look like the following. See getDeviceAuthToken in the reference for descriptions of all parameters and return elements.

POST https://mymusicservice.example.com/smapi HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://www.sonos.com/Services/1.1#getDeviceAuthToken"
Content-Length: 1057
Host: example.com
 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soap:Header>
      <ns:credentials>
         <ns:deviceId>deviceId32578</ns:deviceId>
         <ns:deviceProvider>Sonos</ns:deviceProvider>
      </ns:credentials>
   </soap:Header>
   <soap:Body>
      <ns:getDeviceAuthToken>
         <ns:householdId>householdId653482</ns:householdId>
         <ns:linkCode>8c047510296b11e5a2cb0800200c9a66</ns:linkCode>
      </ns:getDeviceAuthToken>
   </soap:Body>
</soap:Envelope>

Retry Response to getDeviceAuthToken

While your service waits for the user to manually log in through the browser, it should provide to the getDeviceAuthToken call the following SOAP fault response for a few minutes. For details about Sonos error responses, see also Error handling.

  • <faultcode> The value should be Client.NOT_LINKED_RETRY
  • <faultstring> A message indicating the token is not available.The message in this string is placed in the Sonos logs.
  • <ExceptionInfo> A message indicating the response the Sonos app should take. This message string is placed in the Sonos logs.
  • <SonosError> This value must be 5 in order for the Sonos app to respond correctly. Your string tables require a corresponding custom error message with this value and an associated error message string. However, the content of the message string is not displayed or stored anywhere.

For example:

HTTP/1.1 500 Internal Server Error
Content-Type: text/xml; charset=utf8;
Content-Length: 305
 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soap:Body>
      <soap:Fault>
         <faultcode>Client.NOT_LINKED_RETRY</faultcode>
         <faultstring>Access token not found, retry</faultstring>
         <detail>
            <ns:ExceptionInfo>Retry token request.</ns:ExceptionInfo>
            <ns:SonosError>5</ns:SonosError>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

Success Response to getDeviceAuthToken

After the user successfully logs in, your authorization service can create the authorization token. You can use any format you wish for authorization tokens using up to 2048 characters. Your service must be able to decode the user from the token so that it can perform actions on the correct account, such as setting a user favorite. if a user connects to more than one Sonos household, your service must use a different token to represent that user-household combination.

Then your service should send a success response with the following elements. See also getDeviceAuthToken in the reference.

  • <authToken>  Enter the authorization token that your service uses to identify the user at this household.
  • <privateKey>  Enter the private key tied to the authorization token. Use this to support automatic refreshing of tokens. For more see the section on Refreshing Authorization Tokens in Processing authentication credentials for API requests
    If you do not implement refresh tokens, simply include a meaningless string for this value. The string is passed back to your service but not expected to have any meaning or be processed.
  • <userIdHashCode> Enter an ID for the user. This should not contain any identifiable information.
  • <userInfo>  An optional element in which you can enter a user nickname if your service supports it.

For example:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 247
 
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soap:Body>
      <ns:getDeviceAuthTokenResponse>
         <ns:getDeviceAuthTokenResult>
            <ns:authToken>faf7a000296b11e5a2cb0800200c9a661a2cab50296c11e5a2cb0800200c9a66</ns:authToken>
            <ns:privateKey>alwaysReauthenticate</ns:privateKey>
         </ns:getDeviceAuthTokenResult>
      </ns:getDeviceAuthTokenResponse>
   </soap:Body>
</soap:Envelope>