Calling CRM from ASP.NET using impersonation to ActOnBehalfOf the logged in user

UPDATE: Please review the comments for this post.  There is a better, easier way to do this using OAuth that works with both the SOAP and REST/OData service.

Sometimes you need to run ASP.NET code outside of Dynamics CRM to achieve your goals.  This usually manifests itself either as a page embedded in CRMs main content area which is accessible via a link in the sitemap similar to the following:



Another place this is often used is embedding external content through an IFrame in a CRM form.  The general approach is covered in the SDK:

Implement Single Sign-on from an ASPX Webpage or IFRAME

Walkthrough: Single Sign-on from a Custom Web Page

Of course, your code will usually need to call back into Dynamics CRM through the organization (web) service to do things like CRUD on CRM data, etc.  In this scenario, you want CRM to execute code under the context of the logged in user.  The CRM SDK covers how to do this here:

Impersonate Another User

Sample: Impersonate Using the ActOnBehalfOf Privilege

See my CRM Online & Windows Azure Series post for a walkthrough of the Single Sign On (SSO) configuration.  The goal of this post is to bring all of these concepts together in as simple of a “hello world” style code sample as possible.  The sample code is actually the code for the embedded page in the screenshot above (called ActOnBehalfOf.aspx).  The solution is made up of an ASP.NET web form, some code behind the web form, and a helper class I built.  In order to get this code to compile, you are going to have to add the necessary .NET assembly references and fix some of the namespaces.  I’ll leave that exercise to you.


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ActOnBehalfOf.aspx.cs" Inherits="AdfsEnabledReportViewerWebRole.ActOnBehalfOf" %>
    <head runat="server">
        <form id="form1" runat="server">
                <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
                        <asp:BoundField DataField="Id" HeaderText="Id" />
                        <asp:BoundField DataField="Name" HeaderText="Name" />


 1: using System;
 2: using System.Linq;
 3: using Microsoft.Xrm.Client;
 4: using Microsoft.Xrm.Sdk.Client;
 6: namespace AdfsEnabledReportViewerWebRole
 7: {
 8:     public partial class ActOnBehalfOf : System.Web.UI.Page
 9:     {
 10:         protected void Page_Load(object sender, EventArgs e)
 11:         {
 12:             var contextConnection = ActOnBehalfOfHelper.CreateContextAndConnection();
 13:             CrmConnection conn = contextConnection.Connection;
 14:             OrganizationServiceContext ctx = contextConnection.Context;
 16:             // CallierId is what forces CRM to execute the API calls within the security context of the CRM User
 17:             conn.CallerId = ActOnBehalfOfHelper.GetCallerId();
 19:             var accountQuery = from a in ctx.CreateQuery<Account>()
 20:                         select new Account
 21:                         {
 22:                             Id = a.Id,
 23:                             Name = a.Name
 24:                         };
 26:             var accounts = accountQuery.ToList();
 28:             GridView1.DataSource = accounts;
 29:             GridView1.DataBind();
 30:         }
 31:     }
 32: }

If you’ve reviewed the resources in this post, then ActOnBehalfOf.aspx and ActOnBehalfOf.aspx.cs should be pretty self explanatory.  It’s a page with a GridView.  The code behind queries CRM for data using the organization service.  Note that Account from line 19 comes from a class file where I used crmsvcutil.exe to generate the class.  I always use Erik Pool’s approach to only generate classes I need in my code.  I digress.  The code sets the CallerId property of the CrmConnection object instance before executing the code.  By doing this, CRM will execute all calls made to through the OrganizationServiceContext instance as the CRM user based on the CallerId value passed in.  CallerId is the GUID of the CRM user who needs to be impersonated.  The ActOnBehalfOfHelper does the real work to get the proper GUID based on the claims available to the ASP.NET page.  Specifically, it uses the UPN claim value to find the CRM user.  Once the CRM user is found, the code returns the Id of the CRM user as a GUID. 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.IdentityModel.Claims;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk.Client;
namespace AdfsEnabledReportViewerWebRole
    public static class ActOnBehalfOfHelper
// ReSharper disable InconsistentNaming
        private const string CRM_CALLERID = "CRM_CALLERID";
// ReSharper restore InconsistentNaming
        public static ContextConnection CreateContextAndConnection()
            var contextConnection = new ContextConnection();
            // Connect to CRM with a single named user (i.e. system account / trusted subsystem model) who has the ActOnBehalfOf privelege
            contextConnection.Connection =
            contextConnection.Context =
                new OrganizationServiceContext(new OrganizationService(contextConnection.Connection));
            return contextConnection;
        public static Guid GetCallerId()
            Guid callerId;
            var contextConnection = CreateContextAndConnection();
            var ctx = contextConnection.Context;
            // NOTE: I am caching the CallerId to minimize calls to the CRM Organization Service.
            // For production code, you should not store the CallerId in plain text in a cookie.
            // Malicious code, once authenticated, can change the cookie value and execute as another caller.
            // You could apply encryption when creating the cookie and decryption when reading 
            // the cookie value:
            // You could even encrypt/decrypt the cookie name to obfuscate the purpose of the cookie.
            // Alternatively, find a different approach to cache the CallerId value (ASP.NET Session for example)
            // or simply don't cache the CallerId.
            HttpCookie callerIdCookie = HttpContext.Current.Request.Cookies[CRM_CALLERID];
            // If the cookie exists, reuse the Guid string value to execute the call as the current user
            // If not, then query CRM to get the Guid of the authenticated user based on the upn claim
            if (callerIdCookie == null)
                ClaimCollection claims = ((IClaimsIdentity) HttpContext.Current.User.Identity).Claims;
                IEnumerable<Claim> claimQuery = from c in claims
                                                    c.ClaimType ==
                                                select c;
                Claim upnClaim = claimQuery.FirstOrDefault();
                var userQuery = from user in ctx.CreateQuery<SystemUser>()
                                where user.DomainName == upnClaim.Value
                                select user.SystemUserId.Value;
                callerId = userQuery.FirstOrDefault();
                if (callerId == Guid.Empty)
                    // Send HTTP status code of 403
                    // See
                    HttpContext.Current.Response.StatusCode = 403;
                string callerIdString = callerId.ToString();
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(CRM_CALLERID, callerIdString));
                callerId = new Guid(callerIdCookie.Value);
            return callerId;
    public class ContextConnection
        public CrmConnection Connection { get; set; }
        public OrganizationServiceContext Context { get; set; }

Note the comments in the code.  I am doing some caching of the user GUID in a cookie.  Right now, the cookie and cookie value is in plain text.  As I state, this is done for simplicity of the sample.  Make sure you read the comments and make the proper adjustments to protect access to the CallerID GUID from malicious code/callers.


Comments (6)

  1. Pierre Andre Joubert says:


    Thank you for the great article.  I have implemented the code, but I am unfortunately receiving a cast error:

    Unable to cast object of type 'System.Security.Claims.ClaimsIdentity' to type 'Microsoft.IdentityModel.Claims.IClaimsIdentity'.

    Do you possibly have any thoughts in this regard?



  2. Enoch Wallace says:


    Great articles! I already configured SSO with the Azure AD. It works like a charm! Thanks!

    However I have a question. What I want to avoid is providing any username/password credentials for authenticating against Organization web service even if it is a service account. Since with SSO the user is already logged in, can I use his credentials to authenticate against Organization web service?

    Why I want to avoid any username/password providing/storing in our ISV application? A single instance of the application will be used for multiple MS CRM organizations and users. This means that I need to store the credentials of each organization's service account in our DB. And even before that I need to ask our users to create such service account and save them using the configuration page. It is not impossible but I do not see it as a good user experience. Can this be avoided? Can you advice me on that please?

    Thanks in advance!


  3. keydet says:

    @Enoch – The scenario you describe wasn't possible until recently.  However, with some changes made to both CRM Online and Azure AD, this is now possible using OAuth and delegated permissions.  I'll be blogging about it shortly.  I will update these comments when that post is published.

  4. keydet says:

    I never got around to blogging this myself, but I helped Andrew Schultz get the scenario working and he blogged about it:…/how-to-authorize-an-azure-app-to-use-crm-online-web-services-without-asking-the-user-to-authenticate

  5. Mahesh Wankhade says:

    AndrewSchultz and Keydet thanks for nice article.

    Just to you inform you , your below link has started showing expiration error…/how-to-authorize-an-azure-app-to-use-crm-online-web-services-without-asking-the-user-to-authenticate

    last week I have gone through above link. I have also posted my comments there.

    I am using CRM online and Azure hosted web application.

    As in your post you have given example for ODATA call using token , can we use same token to create CRM service connection so that I will not have to hardcode username/password to create CRM connection.

    if yes then can you please provide example for it.

    Uri oUri = new Uri("…/Organization.svc");  

       //** Your client credentials    

       ClientCredentials clientCredentials = new ClientCredentials();  

       clientCredentials.UserName.UserName = "";  

       clientCredentials.UserName.Password = "YourAdminPassword";  

       //Create your Organization Service Proxy  

       OrganizationServiceProxy _serviceProxy = new OrganizationServiceProxy(  





  6. keydet says:

    @Mahesh – If you can user CRM 2015 SDK, then yes.  See:…/microsoft.xrm.sdk.webserviceclient.organizationwebproxyclient_members.aspx

    There is a HeaderToken property.  HTH