Inside SharePoint 2013 OAuth Context Tokens

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:

image

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 https://accounts.accesscontrol.windows.net/tokens/OAuth/2.  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);
        clientContext.ExecuteQuery();
        Response.Write(clientContext.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.

image

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 https://openidtest.uninett.no/jwt 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. 

image

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=\",
\"SecurityTokenServiceUri\":\"https://accounts.accesscontrol.windows.net/tokens/OAuth/2\"}",
    "refreshtoken": "IAAAANc8bAVMWZceOsdfgsdfggbfm7oU_aM7D2qofUpQstMsdfgsdfgfYS0OtbZ-
eY9UQGvlYSl5kpPi913G1AwIVBMxoCux8-bhcCCiaGVo-vuFzrXetdhRGPftQdHh-
1rS5cvDuuQ_bw_mjySIyuHNGSavEs8HUgHY9BOVc3pTGZtZ_nS-
1NbDLYObjnznasdfasdfasdfQreLAeeOpVRY1PGsdfgsdfgOITA3BKhjJFz_40YJMubdHmY2OTS
nqwNnUe-rBBCtfvKt4xFWvdRzTzwfW",

    "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. CacheKey: 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. SecurityTokenServiceUri: The URL for Azure ACS where the token is to be validated.  The URL is https://accounts.accesscontrol.windows.net/tokens/OAuth/2
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 https://msdn.microsoft.com/en-us/library/office/apps/fp179932.aspx

For More Information

configure low-trust apps for on-premises deployments

JWT token format

Tips and FAQs: OAuth and remote apps for SharePoint 2013