Creating Provider Hosted Apps for SharePoint 2013 when your IIS server and SharePoint Servers are in different (non-trusted) domains

I had a customer that wanted to do high trust apps for SharePoint 2013. However, their developer machines were in a different domain than their web servers. TokenHelper is designed to work with either Azure ACS or SharePoint/IIS servers in a Windows domain. After digging into the TokenHelper class that comes with your "”Apps for SharePoint 2013” Visual Studio project, I figured out a way to make this work.

The public method GetS2SClientContextWithWindowsIdentity calls the private method GetClaimsWithWindowsIdentity:

private static JsonWebTokenClaim[] GetClaimsWithWindowsIdentity(WindowsIdentity identity)
       {
           JsonWebTokenClaim[] claims = new JsonWebTokenClaim[]
           {
               new JsonWebTokenClaim(TokenHelper.NameIdentifierClaimType, identity.User.Value.ToLower()),
               new JsonWebTokenClaim("nii", "urn:office:idp:activedirectory")
           };
           return claims;
       }

If you look at the value of identity.User.Value.ToLower(), it turns out that that is a Windows SID. To make this work without a domain, you will have to get the SID of a user from your SharePoint server. You do that via PsGetSID from SysInternals or write a little PowerShell do it (see https://powershellers.blogspot.com/2009/06/how-to-get-computer-sid-using.html).

I extended TokenHelper via extension methods. I don’t like to change generated code in case it gets changed later (although I did have to mark the TokenHelper class partial).

Here is the code that I created so that you can pass a SID:

public partial class TokenHelper
   {

       public static ClientContext GetS2SClientContextWithWindowsSID(
         Uri targetApplicationUri,
         string sid)
       {
           string realm = string.IsNullOrEmpty(Realm) ? GetRealmFromTargetUrl(targetApplicationUri) : Realm;

           JsonWebTokenClaim[] claims = GetClaimsWithWindowsSID(sid);

           string accessToken = GetS2SAccessTokenWithClaims(targetApplicationUri.Authority, realm, claims);

           return GetClientContextWithAccessToken(targetApplicationUri.ToString(), accessToken);
       }
       public static string GetS2SAccessTokenWithWindowsSID(
          Uri targetApplicationUri,
          string sid)
       {
           string realm = string.IsNullOrEmpty(Realm) ? GetRealmFromTargetUrl(targetApplicationUri) : Realm;

           JsonWebTokenClaim[] claims = GetClaimsWithWindowsSID(sid);

           return GetS2SAccessTokenWithClaims(targetApplicationUri.Authority, realm, claims);
       }

       private static JsonWebTokenClaim[] GetClaimsWithWindowsSID(string sid)
       {
           JsonWebTokenClaim[] claims = new JsonWebTokenClaim[]
           {               
               new JsonWebTokenClaim(TokenHelper.NameIdentifierClaimType, sid),
               new JsonWebTokenClaim("nii", "urn:office:idp:activedirectory")
           };
           return claims;
       }

   }

To call this from your app, do this:

TokenHelper.TrustAllCertificates();
var sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]);           
string sid = ""; //replace this
var clientContext = TokenHelper.GetS2SClientContextWithWindowsSID(sharepointUrl, sid);

A full explanation of the TokenHelper class is beyond the scope of this post but you might find this article helpful: https://msdn.microsoft.com/en-us/library/fp179901.aspx.