Kirk Evans Blog

.NET From a Markup Perspective

Inside SharePoint 2013 OAuth Context Tokens

Inside SharePoint 2013 OAuth Context Tokens

Rate This
  • Comments 11

This post will show you how to inspect the SharePoint 2013 context token to better understand how OAuth is used in SharePoint 2013 apps.

First, Some Context

In order to use a context token with SharePoint 2013 apps, you will need to create a provider-hosted app that uses a client ID and a client secret.  This requires that the target SharePoint farm has a trust configured to Azure Access Control Services, or ACS.  Office365 automatically configures this trust for you, so if you create your app using Office365 then this works just fine.  If you create your app using your own SharePoint farm, then you will need to configure low-trust apps for on-premises deployments in order to establish a trust with Azure ACS for your SharePoint farm.

When you use a client ID and a client secret to build your app, you are using Azure ACS as the authentication server.  The OAuth flow looks like this:


This is what I jokingly refer to as “the scary slide”.  It’s not really that scary once you understand it.

  1. User makes a request to SharePoint
  2. SharePoint requests the context token from Azure ACS
  3. The signed context token is returned
  4. The HTML markup for the SharePoint page is sent to the client
  5. If the SharePoint page contents contain a client app part, then a request is sent to the remote web server for the IFrame’s contents.  If the user simply clicked on the app to launch it, then a page in SharePoint called appredirect.aspx is used to redirect to the app’s start URL.  In either case, a context token is sent along with that page request in a form parameter called SPAppToken. 
  6. The context token is a JWT token.  The JWT token is a set of base64 encoded claims.  One claim is named “refreshtoken” that has a base64 encoded value.  One of the claims is “appctx” which contains a child object, one of the properties is SecurityTokenServiceUri with a value  Your app uses the TokenHelper.cs class to extract the refreshtoken and then send it to the SecurityTokenServiceUri to request an access token.
  7. The access token is retrieved from ACS.
  8. The access token is passed to the SharePoint site in the HTTP header Authorization that has a value beginning with “Bearer” and has your access token.  This token is passed in the HTTP header to the CSOM endpoint _vti_bin/client.svc/ProcessQuery when you use the CSOM.
  9. If the app is authorized, SharePoint returns the data requested.
  10. Finally, the app server returns the requested HTML markup as a response. 


The really important thing to understand is what’s passed to your app, the context token.  The context token contains a few key pieces of information necessary for the rest of the plumbing to function.


What’s In Your Wallet?

Now that we’ve walked through the steps of the OAuth dance, let’s take a look at what’s in that context token that is critical to the whole process.  When you use Visual Studio to create a provider-hosted app, the boiler plate code looks like this:

protected void Page_Load(object sender, EventArgs e)
    // The following code gets the client context and Title property by using TokenHelper.
    // To access other properties, you may need to request permissions on the host web.

    var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
    Response.Write(contextToken + "<br/>");
    var hostWeb = Page.Request["SPHostUrl"];

    using (var clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken, Request.Url.Authority))
        clientContext.Load(clientContext.Web, web => web.Title);

Reading that code, you can see that the context token is passed to your app, but it is a base64 encoded string that is unintelligible.  I added a Response.Write statement to write the context token to the page, but you can also see it in Fiddler.  In the following screen shot, I highlighted the SPAppToken HTTP form variable where the context token is passed.


Once you have that context token, you have the base64 encoded value of the context token, which is a JWT token.  The JWT token format is pretty straightforward, and the TokenHelper.cs class in Visual Studio simply parses that JWT token for you.  However, for the curious who want to see what it looks like, you can use a tool like to inspect the JWT token.  Copy the context token string into the “Encoded JWT” text box and the client secret into the “Secret” text box, and then press decode. 


What is returned is the following JSON object, which is a JWT token that contains a set of claims.


    "aud": "4c2df2aa-3d14-4d84-8a79-5a75135e98d0/localhost:44346@d341a536-1d82-4267-87e6-e2dfff4fa325",
    "iss": "00000001-0000-0000-c000-000000000000@d341a536-1d82-4267-87e6-e2dfff4fa325",
    "nbf": 1365177964,
    "exp": 1365221164,
    "appctxsender": "00000003-0000-0ff1-ce00-000000000000@d341a536-1d82-4267-87e6-e2dfff4fa325",
    "appctx": "{\"CacheKey\":\"em1/saZohTOS4nOUZHXMb8QJgyNbkEO86TSe5j9WYmo=\",
    "refreshtoken": "IAAAANc8bAVMWZceOsdfgsdfggbfm7oU_aM7D2qofUpQstMsdfgsdfgfYS0OtbZ-

    "isbrowserhostedapp": "true"
You can now see that the context token contains the refresh token as a base64 encoded value.

What are the claims in the context token?

The following shows the properties for the context token.

aud Short for “audience”, means the principal the token is intended for. The format is <client ID>/<target URL authority>@<target realm>. Based on this information, you can determine the client ID for your app and the realm.  In an on-premise environment, there is typically just one realm, and its identifier matches your farm ID.  For Office 365, this is your tenant ID.
iss Short for “issuer”, this is the principal that issued the token, in the form of <principal ID>@<realm>.  The principal ID value 00000001-0000-0000-c000-000000000000 is ACS. 
nbf Short for “not before”, this is the number of seconds after January 1, 1970 (part of the JWT specification) that the token starts being valid. 
exp Short for “expires”, represents the number of seconds after January 1, 1970 that the token stops being valid.
appctxsender The sender of the token in the form <sender ID>@<realm>.  The value 00000003-0000-0ff1-ce00-000000000000 is the identifier for SharePoint.  For trivia:

ACS 00000001-0000-0000-c000-000000000000
Exchange 00000002-0000-0ff1-ce00-000000000000
SharePoint 00000003-0000-0ff1-ce00-000000000000
Lync 00000004-0000-0ff1-ce00-000000000000
Workflow 00000005-0000-0000-c000-000000000000

The realm will be the tenant ID for Office 365, or the farm ID for your on-premise deployment.
appctx Contains two properties, CacheKey and SecurityTokenServiceUri.
UserNameId + "," + UserNameIdIssuer + "," + ApplicationId + "," + Realm
This is provided so that you can cache the value in a cookie or in session to identify that the user has already authenticated.

The URL for Azure ACS where the token is to be validated.  The URL is
refreshtoken The contents of the refresh token that are sent to Azure ACS.
isbrowserhostedapp Indicates if the request initiated from a user interacting with the browser and not an app event receiver


During Ignite training, I tell the attendees that the most important thing you can understand when building apps for SharePoint is OAuth.  You need to understand the OAuth dance, the reason for the context token, and it is invaluable to understand what the TokenHelper.cs is doing for you when it does things like GetClientContextFromContextToken.  This post goes into some of the details on why this is such an important piece to understand when troubleshooting apps.  You can also see why it is mandatory for apps to SSL due to the nature of information being sent in HTTP. 

You can find more information about the context token, calculating nbf and exp claim values, and links to additional articles at

For More Information

configure low-trust apps for on-premises deployments

JWT token format

Tips and FAQs: OAuth and remote apps for SharePoint 2013

  • Good Post.

  • Nice Post. I did a blog post recently explaining how we can use just HTTP requests to get the accesstoken, which explains some of the internal flow of TokenHelper.

    Here is the post :

  • I used the VS model that mounts to interact with the app, but when the user gets some minutes without interacting with the buttons, the context is null and the error page. The user is then required to start the app again. Know what can be?

  • What could cause an "System.IdentityModel.Tokens.SecurityTokenException: Invalid JWT token. Could not resolve issuer token."?

    The issuer token (iss right?) is supplied by SharePoint (as is everything else in that header apart from the client secret) so what could possibly cause this exception why trying to use context token in TokenHelper?

  • This all worked fine in development but when I published, my web site no longer receives the context token.  What setting did I miss?  

  • I had to use Fiddler to figure out what was going wrong.  I had to adjust the settings in my client ID setup in the seller dashboard to match what was expected as far as the domain and URL.

  • The question is why? Why is Microsoft making it so hard to communicate with SharePoint server. JSOM?CSOM has FormDigest. why can't you just make the same set of calls? To make it worse they never explained in their documentation or sample what is going on behind the scene like you so clearly explained. Thanks for sharing.

  • @Kenny - it's not at all harder, it's actually quite easier than it was in the SOAP web service days as the tooling hides all of this complexity while OAuth opens a ton of new scenarios that weren't possible previously.  As for the FormDigest... that assumes that the CSOM call is rendered in the same page as SharePoint.  If that is the case, then none of this applies as that is not an app, that's just JavaScript in a page, and you don't need any OAuth for that. This scenario is for when your server-side code is running on a completely different server, domain, and possibly even platform than SharePoint.  I can now easily write apps using Java, Node.js, and PHP that communicate with SharePoint... this was difficult using SOAP.

  • Hi Kirk,

    Nice post! BTW, I'm having the same issue as Dave.. When I'm running the webapp locally everything is right, but when I upload it to Azure, SPAppToken is null and it can't authenticate...

    Any thoughts on this?

    Many thanks.

  • @fretwio and @Dave -

    Assuming you are using AppRegNew.aspx, the domain and callback URL are required when registering the app.  If you use them locally, then you would have registered http://localhost.  When publishing to another site (such as Azure Web App) you have to register a new entry with the new domain and callback URL.  These are not editable when using AppRegNew.aspx.

    If you are using the store registration, same thing... you need to update the domain and callback URL.  

  • I am a little baffled about that. Every decent developer must be switching back and forth between testing locally and deploying remotely constantly. Is the intention that they should edit their Web.config to change the client ID each time such a switch is made, or is there a less dumb way to go about it?

Page 1 of 1 (11 items)
Leave a Comment
  • Please add 2 and 5 and type the answer here:
  • Post
Translate This Page