Integrate Sitecore with Alexa

During last month’s Sitecore symposium I had the pleasure to present with my colleague Ben Adamski on expanding the reach of your Sitecore content with voice-activated assistants through an Alexa skill. This blog post will describe the integration discussed during this presentation and will provide some additional details.

Sitecore 9 omnichannel foundation

Sitecore has a solid omnichannel foundation which enables it to act as a headless CMS. Below diagram shows the main integration points exposed by Sitecore out of the box.

Omnichannel Foundation

  1. OData Item Service: this service can be used to query and retrieve any Sitecore item and retrieve it in JSON format.
  2. SXA Layout Service: the SXA layout service supports modelling content as JSON. This is done in the experience editor and uses the same layout engine as regular Sitecore pages. This allows content authors to use the tools they are already familiar with and personalization is supported. Also analytics and tracking are working like a regular Sitecore page as the layout engine is used to render.
  3. xConnect Client API: the xConnect client API needs to be used to retrieve the previous customers’ interactions with Sitecore.
  4. Commerce 9 OData API: any data which resides in Sitecore Commerce can be retrieved using this API.

Integration with the Sitecore services

There are several options to call the Sitecore services mentioned above. They were called from AWS Lambda in our demo during Symposium but there are some other options too:

  1. AWS Lambda: this is AWS’ serverless computing platform. Here are some key considerations for hosting this in Lambda:
    Pro:
    – Relatively simple integration with Alexa. Alexa runs in AWS and integration with Lambda takes just a few clicks and there are many examples online.
    – Little effort required to include Alexa SDK which simplifies integration with Alexa
    Con:
    – Most Sitecore developers are not familiar with Lambda and will need to spend some time getting up to speed
  2. Azure/on-premise: Alexa can call any restful endpoint so the integration layer can be hosted anywhere accessible by AWS so this can be hosted in Azure or your existing on-premise data center:
    Pro:
    – No need to get up to speed with a new platform
    Con:
    – Will require more effort to integrate securely with Alexa

Alexa Skill Kit SDK

There is an Alexa Skill Kit SDK available which makes working with Alexa significantly easier. The SDK is available in Node.js, Java and Python. Getting started with the Node.js SDK is surprisingly simple for C# developers as the new version 2 of the SDK is using async/await and promises instead of the callback based style which was previously used. Below is a code sample which runs when the user performs a search in the Alexa Skill. There are a few things to note about this:

  • This uses the Item Service to perform the search. The query is built on line 9.
  • The call to execute and await the search query is on line 11 and the httpGet method is starting at line 31. This calls the Item Service.
  • Methods from the Alexa Skill Kit SDK are used extensively for example on lines 23-28 to send the output speech to Alexa.

const SearchIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'SearchIntent';
    },
    async handle(handlerInput) {
        const searchTerm = handlerInput.requestEnvelope.request.intent.slots.SearchTerm.value;

        const query = '/item/search?term=' + searchTerm;

        const response = await httpGet(query);

        var searchResult = "";
        var cnt = 0;

        for (var i = 0; i  {
        const request = http.request(options, (response) => {
            response.setEncoding('utf8');
            let returnData = '';

            if (response.statusCode = 300) {
                return reject(new Error(`${response.statusCode}: ${response.req.getHeader('host')} ${response.req.path}`));
            }

            response.on('data', (chunk) => {
                returnData += chunk;
            });

            response.on('end', () => {
                resolve(JSON.parse(returnData));
            });

            response.on('error', (error) => {
                reject(error);
            });
        });
        request.end();
    });
}

Alexa Skill Interaction Model

The focus on this blog post is on the Sitecore integration with Alexa but it is important to understand that there is some Alexa work as well, specifically setting up the interaction model. There are 3 main entities in the interaction model:

  • Intents: the intent defines what the user is trying to achieve. The code above is handling the search intent.
  • Utterances: these are phrases likely spoken by the user to invoke the intent. Most intents will have multiple utterances. In above example an utterance mapped to the search intent could be “please search for “
  • Custom slot types: slot types hold the values for phrases the user says, but cannot be part in the utterance. In above example the “search term” is an example of a slot type and Alexa will automatically populate it with the search team spoken by the user.

The interaction model is stored in json, below is the json from the search intent. More information about the interaction model can be found here.

{
  "name": "SearchIntent",
  "slots": [
    {
      "name": "SearchTerm",
      "type": "AMAZON.SearchQuery"
    }
  ],
  "samples": [
    "please search for {SearchTerm}",
    "search for {SearchTerm}",
    "what is {SearchTerm}"
  ]
}

Integrated Alexa with other channels

It is important to built an Alexa Skill which is integrated with your brand’s other channels. A user is not going to have a good voice experience with a disconnected Alexa skill as this skill is not able to leverage customer interaction information from other channels to deliver a relevant and personalized experience. It is also important to understand customers behavior across all channels to get a single view of the customer and to provide relevant content to each user.

With the customer’s permission Alexa can return the location of the customer. This can be used to provide more relevant location based content to the user. During our presentation we showed location based personalization with Sitecore and Alexa. The location cannot be used integrate between channels as Amazon does not allow use of the location to associate the user to a customer with the same address. Amazon can reject or suspend your skill if they find out this is being done. More information about the use of location can be found here

Account linking is the feature which should be used to connect Alexa with other channels. Account linking connects the identity of the Alexa user to an identity in a third party system through OAuth 2.0. Setting this up will be easier if the Sitecore solution runs on version 9 since this supports federated authentication. More information about account linking can be found here.

Sitecore use OAuth2 login with OWIN

As an experiment I wanted to see if it would be possible to use the social logins such as google with Sitecore using a similar approach as a plain MVC app. More details around doing this without Sitecore can be found here Notice that the code used in ASP .NET MVC relies on OWIN authentication middleware and ASP .NET Identity. This makes sense in ASP .NET, but we’ll have to reconsider this when integrating with Sitecore. A similar post using OWIN in Sitecore using Federated Authentication can be found here.

Sitecore and OWIN

Using OWIN with Sitecore makes sense, it is certainly possible to not use OWIN and rely on a custom implementation instead. There are some blog posts as well that will help you get started.

Given the security implications of getting a custom implementation slightly incorrect, it is highly recommended to use a proven solution like the OWIN middleware.

Additionally OWIN is widely used in regular ASP .NET applications. OWIN comes as a nuget package which makes it straightforward to update and take advantage of new features.

Sitecore and ASP .NET Identity

Using Sitecore with ASP .NET Identity does not make sense to me as Sitecore still uses ASP .NET membership. Using ASP .NET Identity would add another component that I could not see a use or benefit for, but please let me know in case anyone does. Some code in this post is from this post which describes how to use OWIN without ASP .NET Identity in ASP .NET MVC.

Configuring OWIN Middleware

Below code configures the OWIN middleware to use google authentication:

using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Google;
using Owin;

namespace SitecoreOwinGoogle
{
    public partial class Startup
    {
        private void ConfigureAuth(IAppBuilder app)
        {
            var cookieOptions = new CookieAuthenticationOptions
            {
                LoginPath = new PathString("/Login")
            };

            app.UseCookieAuthentication(cookieOptions);

            app.SetDefaultSignInAsAuthenticationType(cookieOptions.AuthenticationType);

            app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
            {
                ClientId = "your client id",
                ClientSecret = "your client secret"
            });
        }
    }
}

Notice in the usings that only OWIN is referenced, there are no ASP .NET Identity referenes added. ClientId and ClientSecret can be obtained from from Google Developers Console Never store passwords and other sensitive data in source code, for best practices see here

Login Through Google

In the OWIN middleware /Login is set as the login path. This can be set to a different path as well as long as there is code running when that path is hit to handle the login. I added a controller rendering here to transfer control to google:

public ActionResult Login(string returnUrl)
{
    return new ChallengeResult("Google",
      string.Format("/Login/ExternalLoginCallback?ReturnUrl={0}", returnUrl));
}

The ExternalLoginCallback will redirect the user to secure page that he was trying to navigate to before the OWIN middleware kicked in. It is important to run this code in the path specified in the redirectUri parameter on the ChallengeResult constructor, in this case “/Login/ExternalLoginCallback”.  Again I’m using a controller rendering for this.

public ActionResult ExternalLoginCallback(string returnUrl)
{
    return new RedirectResult(returnUrl);
}

I have used the same ChallengeResult class as ASP .NET MVC:

// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";

internal class ChallengeResult : HttpUnauthorizedResult
{
    public ChallengeResult(string provider, string redirectUri)
        : this(provider, redirectUri, null)
    {
    }

    public ChallengeResult(string provider, string redirectUri, string userId)
    {
        LoginProvider = provider;
        RedirectUri = redirectUri;
        UserId = userId;
    }

    public string LoginProvider { get; set; }
    public string RedirectUri { get; set; }
    public string UserId { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
        if (UserId != null)
        {
            properties.Dictionary[XsrfKey] = UserId;
        }
        context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
    }
}

Redirect back to Sitecore

After google completed validating the user it will redirect back to Sitecore. By default OWIN expects this at /signin-google. Here OWIN will set the cookie used for the CookieAuthentication. Make sure to configure this page as an authorized redirect URI in google’s console.

Sitecore will try to handle the request which is made to /signin-google, Sitecore should not touch this request and let OWIN handle it. The easiest way to achieve this is by adding this page to the IgnoreUrlPrefixes setting. From there OWIN will call the callback URL specified in the ChallengeResult and this will redirect back to page that is secured.

Securing pages

That is all for the OWIN and OAuth code. Now that this is in place a controller action method can be decorated with the Authorize attribute to trigger the authentication flow. Below diagram shows the end-to-end flow:

Authentication flow

Further considerations

As mentioned before this blog post is a start in using OWIN with OAuth2 in Sitecore. However there are many other items to explore:

  • Multisite support: perhaps you have a multisite solution and some sites need social logins and other sites need a different login method. OWIN supports branching the pipeline to allow for different configurations based on a condition e.g. hostname
  • Support different social provider: this blog post only works with google, but OWIN supports several different logins like Facebook, Twitter, Linkedin or Microsoft.
  • Logoff: this post only covers login, but it should be fairly straightforward to implement logoff in a similar fashion.
  • Sitecore Virtual Users: the authentication in this post is basic, either you are successfully logged in from google or you are not. Most real world applications are more complicated and different users have different permissions. In these cases it can be helpful to create a Sitecore virtual user and assign Sitecore roles.
  • OAuth2 scope: there is a scope parameter which supports retrieving additional information about the user from google. The users will have to accept this first on the consent screen when they use google’s system to log in.

Summary

This post showed how to set up OWIN with Sitecore and OAuth2. Using OWIN significantly simplified working with OAuth2 and google. There are a number of additional considerations that must be taken into account before using this in a production scenario.