More TroubleShooting Tips for High Trust Apps on SharePoint 2013

Hey, I'm an app guy, I like doing dev, but honestly - I may go hoarse screaming at my computer if I have to track down one more "The issuer of the token is not a trusted issuer" problem with my new SharePoint apps. To try and help you save your own voice (and sanity) I'm going to start a list here of things that I look for when I get this issue. As I discover new and exciting ways of both invoking this error and resolving it, I will just update the post here and throw an "UPDATED!" doo hickey below. 

It's important to remember when I say "high trust app", that means that you are NOT using ACS as the trust broker for your SharePoint app; instead your are creating the OAuth token and signing it with your own certificate. I know we have this whole process documented out there somewhere so I'm not going to try and describe that here again. I'm going to assume you read it, you've been trying it, and now you are ready to give the one-finger salute to your monitor. So, that being said, here are some of the ways I've seen this error occur:

  1. Add to the SPTrustedRootAuthority list - when you use a certificate to sign your OAuth tokens, you need to create a New-SPTrustedRootAuthority. Just like the New-SPTrustedIdentityTokenIssuer in SharePoint 2010, you need to add the token signing certificate and every certificate in the chain to SharePoint's list of trusted authorities. You can follow the same steps for this process as I described in this post: https://blogs.technet.com/b/speschka/archive/2010/02/13/root-of-certificate-chain-not-trusted-error-with-claims-authentication.aspx. Just ignore the stuff about exporting the certificate from ADFS - I'm assuming you created your certificate for your high trust apps via some other means - public root CA like GoDaddy, VeriSign, etc., self-signed cert, or domain issued cert.
  2. Client ID uses all uppercase characters - as I described in another post, make sure that you do NOT use uppercase letters when you plug in the client ID in the AppManifest.xml file of your application, or in the web.config of your web application if you are building a self-hosted solution. For more details see this: https://blogs.technet.com/b/speschka/archive/2012/07/28/an-important-tip-about-client-id-values-for-s2s-apps-in-sharepoint-2013.aspx.
  3. Token issuer not configured as trust broker - I also described this problem in another post here: https://blogs.technet.com/b/speschka/archive/2012/09/27/another-apps-for-sharepoint-tip-with-the-error-quot-the-issuer-of-the-token-is-not-a-trusted-issuer-quot.aspx. The net of this is make sure when you create your New-SPTrustedSecurityTokenIssuer that you include the -IsTrustBroker flag.
  4. UPDATED!: Missing the IssuerId key in web.config - In order to use the trust broker feature of apps in SharePoint 2013, your application has to know what the IssuerId of the trust broker is when it creates the JWT token it sends to SharePoint. The way it knows this is by looking in web.config for an app property called IssuerId. It goes the same place in your application's web.config as ClientId, ClientSecret, etc. It just looks like this: <add key="IssuerId" value="e9134021-0180-4b05-9e7e-0a9e5a524965"/>.
  5. UPDATED!: Using the Office Tools RTM Preview for Visual Studio - there actually is a little bug in the RTM Preview bits, which is fixed in Preview 2. The code that sends that authorization token to SharePoint doesn't look for the IssuerId element in web.config, instead it sends a different value. What it sends and why is not really important; what IS important is that the way you work around this with that version of the tools is to always use the IssuerId value for the SPTrustedSecurityTokenIssuer in the ClientId key in your web.config. As you get the Preview 2 bits please install them right away and change the ClientId to a unique GUID that you create and register (with Register-SPAppPrincipal as explained below). You don't want the ClientIds to all be the same because it identifies what application signed the OAuth token, and is used throughout the SharePoint UI. If you ever need to do any troubleshooting or auditing it will be a problem if all apps use the same value. UPDATED Part 2!: The Preview 2 bits are now available! You can find them at https://www.microsoft.com/web/handlers/WebPI.ashx?command=GetInstallerRedirect&appid=OfficeToolsForVS2012GA.
  6. UPDATED!: Authentication not Configured on Provider Hosted App - you may have gotten everything working and then create a provider hosted app hosted in IIS instead of IIS Express (see here for more details on this process: https://blogs.technet.com/b/speschka/archive/2013/06/12/converting-a-vs-net-web-for-a-provider-hosted-sharepoint-app-to-a-full-blown-web-or-console-application.aspx). Despite that, when the code runs in your app you get access denied again. Here's a tip - set a breakpoint in TokenHelper.cs in the GetClaimsWithWindowsIdentity method, and then look at the identity.User.Value. If you see a very short SID value, like S-1-5-17, then that probably means it's the anonymous account for IIS. The SID for a "real" user is much longer, something like S-1-5-21-1644491937-1935655697-1957994488-2138. Remember that the way OAuth works (in the most common case with SharePoint Apps) is that it checks to make sure BOTH the app AND the user have rights to the content. In most cases the anonymous user account will not have rights, and so you will get an access denied error message. To fix this you need to go into IIS and find your provider hosted app, then disable Anonymous access and enable Windows authentication. I recommend restarting the IIS virtual server for your hosted app, then try again.

Now, there's also a related issue worth noting: suppose you "think" you've gotten past this error, but then you get an Access Denied error when trying to retrieve content from a SharePoint site in your self-hosted application? Well what that can mean is:

  1. The ClientId value in your AppManifest.xml file for your SharePoint app does not match the ClientId value in the web.config for your self-hosted app. We're making improvements to the Visual Studio tools that should alleviate this problem going forward.

Now a nearly equally good question is how do I track down stuff like this when it happens? Well if it were easy I wouldn't be hoarse and saluting my monitor with one finger. But here's the best data sources I've found so far to use when this problem happens. Again, as I find new things I will add to the list:

  1. ULS logs - a perennial favorite, especially at holiday parties, I like to crank open the ULS logs and just admire the sheer volume of data. Okay, that was sarcasm. But what you can really do is go into Central Admin, Monitoring, Configure diagnostic logging. Expand the SharePoint Foundation category and select the following items: App Auth, Application Authentication, Authentication Authorization and Claims Authentication. Setting the logging and trace level to Verbose for these guys and save your changes, then go and try and launch your application again. Grab one of the many ULS log viewing tools to see your request come in and being processed. It's a good way to gather hints about your app authentication issues.
  2. Fiddler - also a fan favorite, Fiddler is very useful for these situations too. What you will most frequently see is a 401 unauthorized error (like whenever the underlying issue is the "issuer of the token is not a trusted issuer"). If you look at the last frame in the request and click on the Headers tab in the Response frame you will see a WWW-Authenticate cookie that looks something like this: Bearer realm="8a96481b-6c65-4e78-b2ef-a446adb79b59",client_id="00000003-0000-0ff1-ce00-000000000000",trusted_issuers="<e9134021-0180-4b05-9e7e-0a9e5a524965@8a96481b-6c65-4e78-b2ef-a446adb79b59,00000003-0000-0ff1-ce00-000000000000@8a96481b-6c65-4e78-b2ef-a446adb79b59>" . So what can you take away from this? Well I know from looking at this that it expects my ClientId value to be e9134021-0180-4b05-9e7e-0a9e5a524965 and it expects my realm to be 8a96481b-6c65-4e78-b2ef-a446adb79b59. The ClientId value is easy enough to check - I can go look in my AppManifest.xml file and my web.config for my self-hosted app. It's extremely unlikely that your realm would be wrong, but you can always verify by running this PowerShell:

$spurl ="https://foo"
$spsite = Get-SPSite $spurl
$realm = Get-SPAuthenticationRealm -ServiceContext $spsite
$realm

That will output to the screen whatever your realm is. Finally, there's one other thing you can do to verify - make sure that you have an appPrincipal created for the ClientId you are using. Again here's some PowerShell you can use to check that, using my WWW-Authenticate header info from above:

Get-SPAppPrincipal -NameIdentifier <e9134021-0180-4b05-9e7e-0a9e5a524965@8a96481b-6c65-4e78-b2ef-a446adb79b59> -Site https://foo

If you get an error or no results then you know you don't have a valid SPAppPrincipal so you need to create one using PowerShell. For completeness, here's an example of that:

$clientId = "some guid you create"
$spurl ="https://foo"
$spsite = Get-SPSite $spurl
$realm = Get-SPAuthenticationRealm -ServiceContext $spsite
$fullAppIdentifier = $clientId + <'@'> + $realm
$appPrincipal = Register-SPAppPrincipal -NameIdentifier $fullAppIdentifier -Site $spsite.OpenWeb() -DisplayName "My Cool App"

Okay, and with that, my list of high trust app troubleshooting tips is exhausted for today, as am I. When or if I have more news I will update this post.