Building multi-tenant web Apps talking to CRM

I wanted to try to capture the shortest path to creating an ASP.NET site that use Azure AD to authenticate the user and then used that to get an Authorization Token to access CRM on behalf of the user. All of this is done without ever having the user provide you their credentials to CRM.

Disclaimer: I did use VS 2015 CTP6 to build this, but I believe most of it will still be valid for VS 2013 as well. I just happen to be spending a lot of time in VS 2015 right now. This also assumes you have some working knowledge of MVC, and some of Azure AD. I wanted to keep this as short as possible. There is one place you will see a hard coded URL, ultimately that could be replaced using the discovery service or by having the user provide the URL.

1) Create a new ASP.NET - Choose MVC from the template list - it alread has some of the plumbing built in. Click the Change Authentication and make the following choices:

  • Work and School Accounts
  • Cloud - Multiple Organizations
  • Choose one of your domains from the account you logged into

2) Run the app - login you should see a consent dialog like the following
3) Now go into the Azure Portal and Add Dynamics CRM permissions to the application
4) Generate a new Key and paste that into web.config in a new setting called ClientSecret
5) In App_Start\Startup.Auth.cs add the following line after it retrieves ClientId
private string ClientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"] 6) Add a NuGet reference to Microsoft.Identity.Model.Clients.ActiveDirectory
7) Add the following code inside the Notifications as shown in the picture

    AuthorizationCodeReceived = (context) =>
        var code = context.Code;

        ClientCredential credential = new ClientCredential(ClientId, ClientSecret);
        string tenantID = 
        string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

        Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext authContext =
          new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(
               string.Format("{0}", tenantID));
        AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
            code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), 
            credential, "Microsoft.CRM");

        return Task.FromResult(0);

7B) Add the following line in the same method below where it gets the ClientID
ClientSecret = ClientSecret,

8) Build and resolve any reference problems
9) Add a NuGet reference to CRM Core Assemblies
10) Add the following code to replace the About action in the HomeController.cs

       public async Task<ActionResult> About()
        string ClientId = ConfigurationManager.AppSettings["ida:ClientId"];
        string ClientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"];
        string signedInUserID 
            = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
        string tenantID 
            = ClaimsPrincipal.Current.FindFirst("").Value;
        string userObjectID 
            = ClaimsPrincipal.Current.FindFirst("").Value;

        AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}", tenantID));
        ClientCredential credential = new ClientCredential(ClientId, ClientSecret);
        var result = await authContext.AcquireTokenSilentAsync("Microsoft.CRM", 
            credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));

        OrganizationWebProxyClient service = new OrganizationWebProxyClient(
            new Uri(""), false);
        service.HeaderToken = result.AccessToken;
        service.SdkClientVersion = "7.0";
        var whoamiResult = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
        ViewBag.Message = "User ID is " + whoamiResult.UserId;
        return View();

11) Build and resolve any issues
12) Run it and Test it by clicking on About after you log-in - if you did everything right you would see something like the following

comments powered by Disqus