3. Developing with OAuth
There are three important requirements to keep in mind when developing cloud-hosted apps that will be installed within an Office 365 tenancy. First, the app
manifest file must be properly configured to indicate whether the app
is a provider-hosted app or an autohosted app. Secondly, the web.config
file in the ASP.NET project for the remote web must be configured to
track the client ID and the client secret. Finally, you must write
server-side code that creates and manages access tokens.
The app manifest file for a provider-hosted app must be configured with a <RemoteWebApplication> element that contains an inner ClientId attribute which tracks the GUID identifying an app principal.
<AppPrincipal>
<RemoteWebApplication ClientId="00000000-0000-0000-0000-000000000001" />
</AppPrincipal>
If you are developing an autohosted app, on the other hand, the app manifest should be configured with an <AutoDeployedWebApplication>
element. The <AutoDeployedWebApplication> element is different
from the <RemoteWebApplication> element because it does not
contain an attribute for a client ID.
<AppPrincipal>
<AutoDeployedWebApplication/>
</AppPrincipal>
The next aspect of configuring a cloud-hosted app for use in the Office 365 environment is configuring the web.config file of the remote web with two settings that are set the same, regardless of whether you are developing a provider-hosted app or an autohosted app. In particular, you must add two appSettings variables into the web.config file to track the client ID and the client secret. These appSettings variables must be named ClientId and ClientSecret.
<configuration>
<appSettings>
<add key="ClientId" value="00000000-0000-0000-0000-000000000001" />
<add key="ClientSecret" value="rdYuzdeP9LX67rJJLTDjL1E5pvqbrLe4VTs2apITF4g=" />
</appSettings>
</configuration>
At this point, you might be wondering what these two appSettings variables are for. As it turns out, these two variables are used by a utility class named TokenHelper
that Visual Studio 2012 automatically adds to ASP.NET projects that
will be used to implement a remote web. The last step in getting up and
running with OAuth is learning how to program with the TokenHelper class to create access tokens and to pass these access tokens when making CSOM and REST calls back to the SharePoint host environment.
Programming with the TokenHelper class
If you plan on developing cloud-hosted apps, you must learn to work with the TokenHelper class. The TokenHelper
class provides a public set of static methods for working with several
different types of security tokens including context tokens, refresh
tokens, and, most importantly, the access tokens.
Let’s start with a simple example. Examine the server-side C# code in Example 1 which shows an implementation for the Page_Load
method. This code is very similar to the “hello world” code snippet
that Visual Studio 2012 automatically adds to the start page of a
cloud-hosted app that uses OAuth. This code has been written to
retrieve the context token passed by the SharePoint host environment
and then to obtain an access token from Windows Azure ACS.
Example 1. The TokenHelper class used to acquire access tokens to make authenticated CSOM and REST API calls
protected void Page_Load(object sender, EventArgs e) {
// get context token from incoming HTTP form variable
var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
// get host web URL from incoming query string parameter
var hostWeb = Page.Request["SPHostUrl"];
// call to Window Azure ACS to acquire access token
using (var clientContext =
TokenHelper.GetClientContextWithContextToken(hostWeb,
contextToken,
Request.Url.Authority)) {
// Make CSOM call to SharePoint host passing access token
clientContext.Load(clientContext.Web, web => web.Title);
clientContext.ExecuteQuery();
// display site title on start page
Response.Write(clientContext.Web.Title);
}
}
Now that you have seen a simple example of using the TokenHelper
class, it’s time to explain how to program against this class in a bit
more detail. When a user is redirected from a host web in an Office 365
tenancy
to the start page in the remote web, the SharePoint host environment
passes several important pieces of data to the app’s remote web by
using an HTTP POST operation.
For example, the SharePoint host environment passes several querying string parameters, including one named SPHostUrl
which contains the base URL of the host web. When you are writing
server-side code behind the start page for a cloud-hosted app, you can
retrieve the host web URL by using the following code:
string urlHostWeb = Request.QueryString["SPHostUrl"]
In addition to query string parameters, the SharePoint host
environment also passes several form parameters when posting to the
start page in the remote web, including one named SPAppToken, which contain the context token. You can access the context token as a raw string by using the following code:
string contextTokenString = Request.Form["SPAppToken"]
As you have already seen in Example 1, you can retrieve the context token by using a TokenHelper method named GetContextTokenFromRequest. When you make the call to GetContextTokenFromRequest, you pass the ASP.NET Request object as the one and only parameter value.
// when calling GetContextTokenFromRequest, you must pass the ASP.NET Request object
string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);
The code in Example 1 demonstrates passing the context token as a raw string when calling GetClientContextWithContextToken.
The implementation of this method extracts the refresh token from the
context token and then uses it to call to Windows Azure ACS to obtain
an access token. After the access token has been returned, the GetClientContextWithContextToken
method uses it to initialize a CSOM session with a special client
context that automatically passes the access token when sending a
request to execute CSOM commands on the SharePoint host environment.
If you need to read information from inside the context token, you
can convert the context token string to a strongly typed object by
calling the TokenHelper method ReadAndValidateContextToken.
string remoteWebUrl = Request.Url.Authority;
string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);
SharePointContextToken contextToken;
contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString, remoteWebUrl);
The call to ReadAndValidateContextToken returns a SharePointContextToken object that makes the information inside the context token accessible to your code through simple properties. The code in Example 2 demonstrates the type of information that you can read from the context token.
Example 2. Accessing information within the context token
string remoteWebUrl = Request.Url.Authority;
string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);
SharePointContextToken contextToken;
contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString,
remoteWebUrl);
// ID of the current user on behalf of which the current call is executing
string nameId = contextToken.NameId;
// Client ID of the app principal used for external authentication
string clientId = contextToken.ActorToken.ActorToken.Id;
// ID of the hosting tenancy in Office 365
string realm = contextToken.Realm;
// Environment ID for Office 365
string targetPrincipalName = contextToken.TargetPrincipalName;
// ID of the authentication server which is Windows Azure ACS
string issuer = contextToken.Issuer;
// URL used when communicating with Windows Azure ACS
string securityTokenServiceUri = contextToken.SecurityTokenServiceUri;
// time when context token became valid
DateTime validFrom = contextToken.ValidFrom;
// time when context token expires
DateTime validTo = contextToken.ValidTo;
// refresh token
string refreshToken = contextToken.RefreshToken;
// caching key for caching refresh tokens and access tokens
string cacheKey = contextToken.CacheKey;
If you look toward the end of Example 2,
you can see that the code demonstrates how to retrieve both the refresh
token and the cache key from the context token. The refresh token is
what the app must pass to Windows Azure ACS to obtain an access token.
Although you do not have to work directly with refresh tokens in all
scenarios, it can be helpful to store refresh tokens in a database
where they are good for 6 months to retrieve access tokens. Remember that an access token is only good for 12 hours.
Recall that all refresh tokens and the majority of access tokens
contain information about one specific user. Therefore, any scheme you
design to cache or store refresh tokens and/or access tokens must
ensure that caching is user-specific when required. It would be bad to
use the refresh token associated with one user to retrieve an access
token for a different user.
The context token contains a special string value named cacheKey.
The cache key holds a string value that will always be unique for the
combination of current user, the host web site, and app. The idea is
that you can use the cacheKey as a dictionary lookup key when caching or storing access tokens in memory or refresh tokens inside a database.