Working with access tokens
At this point, you have already seen the code required to execute CSOM commands by using OAuth. Executing a REST API call by using OAuth is different because you must work directly with access tokens in your code. Example 3
shows the code required to retrieve an access token. After the access
token has been acquired, it must be converted into a string and added
as an HTTP header before making a REST API call.
Example 3. Making a simple REST API call by using OAuth
// get context token as a SharePointContextToken object
string remoteWebUrl = Request.Url.Authority;
string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);
SharePointContextToken contextToken;
contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString,
remoteWebUrl);
// retrieve host web information
string hostWebUrl = Request.QueryString["SPHostUrl"];
Uri hostWebUri = new ri(hostWebUrl);
string hostWebAuthority = hostWebUri.Authority;
// get access token by passing context token and host web authority
OAuth2AccessTokenResponse accessToken = TokenHelper.GetAccessToken(contextToken,
hostWebAuthority);
// get access token as a base 64 encoded string
string accessTokenString = accessToken.AccessToken;
// prepare HttpWebRequest to execute REST API call
HttpWebRequest request1 =
(HttpWebRequest)HttpWebRequest.Create(hostWebUrl.ToString() +
"/_api/Web/title");
// add access token string as Authorization header
request1.Headers.Add("Authorization", "Bearer " + accessTokenString);
// execute REST API call and inspect response
HttpWebResponse response1 = (HttpWebResponse)request1.GetResponse();
StreamReader reader1 = new StreamReader(response1.GetResponseStream());
XDocument doc1 = XDocument.Load(reader1);
string SiteTitle = doc1.Root.Value;
Let’s step through some of the code in Example 3. There is a call to the TokenHelper method GetAccessToken, which retrieves an access token from Windows Azure ACS. When you call GetAccessToken, you must pass a strongly typed context token and the authority of the host web.
// get access token by passing context token and host web authority
OAuth2AccessTokenResponse accessToken = TokenHelper.GetAccessToken(contextToken,
hostWebAuthority);
// get access token as a base 64 encoded string
string accessTokenString = accessToken.AccessToken;
When passing the second parameter for the host
web authority, you must pass the URL of the host web but without the
protocol in front. For example, the host web authority is a string such
as tenancy01.sharepoint.com, as opposed to the host web URL, which has the protocol at the beginning with a value such as https://tenancy01.sharepoint.com.
You can see that calling GetAccessToken returns a strongly typed object of type OAuth2AccessTokenResponse.
However, you must usually work with the access token in its raw form as
a Base64-encoded string. You retrieve the string for the access token
by reading the AccessToken property of the OAuth2AccessTokenResponse object.
The code in Example 3 demonstrates creating a HttpWebRequest object and adding the string-based access token as an HTTP header named Authorization. You should take note that the Authorization header value is created by combining the word “Bearer” together with the access token, with a blank space between them.
string restUri = hostWeb + "/_api/Web/title";
HttpWebRequest request1 = (HttpWebRequest)HttpWebRequest.Create(restUri);
// add access token to Authorization header
request1.Headers.Add("Authorization", "Bearer " + accessTokenString);
Working with app-only access tokens
In the majority of scenarios, an access token will carry the
identity of the current user in addition to the identity of the app
itself. However, there are scenarios for which it makes sense to create
an access token that contains app identity but not user identity. This
type of security token is known as an app-only access token.
As discussed earlier in the chapter, there are two primary scenarios in which you should use app-only access
tokens. The first scenario involves a requirement to elevate the
permissions for an app so that they are not constrained by the
permissions of the current user. For example, an app-only access token
makes it possible for an app to create a list in the host web even when
the current user lacks the permissions to do so.
The second scenario in which it makes sense to create app-only
access tokens is during a time when there is no current user. This
might be the case if an app runs a batch job every night at midnight to
update a set of document in the host web. In this scenario, the app is
running but not in the context of any specific user. However, the app
is still required to create an access token to make CSOM or REST API
calls against the host web.
You can retrieve an app-only access token by calling the TokenHelper method named GetAppOnlyAccessToken.
This method accepts three parameters, including the target principal
name, the host web authority, and the realm which identifies the
hosting tenancy in Office 365.
// get app-only access token as a strongly-typed object
OAuth2AccessTokenResponse appOnlyAccessToken =
TokenHelper.GetAppOnlyAccessToken(contextToken.TargetPrincipalName,
hostWebAuthority,
contextToken.Realm);
// get access token in a string form to pass across the network
string appOnlyAccessTokenString = appOnlyAccessToken.AccessToken;
After you have obtained the app-only access token from Windows Azure
ACS and converted it into its string format, you can use it to set up
the Authorization header, just as you do with standard access tokens, as shown back in Example 3.
If you want to execute CSOM commands by using app-only permissions, you
must first obtain the string value for an app-only access token. You
can pass the app-only access token string when calling the GetClientContextWithAccessToken method to establish a new CSOM session, which executes its commands by using app-only permissions.
ClientContext appOnlyClientContext =
TokenHelper.GetClientContextWithAccessToken(hostWebUrl, appOnlyAccessTokenString);
Acquiring permissions on the fly by using authorization code
So far, this chapter has discussed authentication and authorization
scenarios involving SharePoint apps that have been installed into a
specific SharePoint tenancy. SharePoint 2013 provides another option
which can be used by standard websites that were not developed as
SharePoint apps. This allows any type of website on the Internet to
request permissions to access a SharePoint 2013 site on the fly.
Although this approach does not involve creating or installing a
SharePoint app, it does require you to preregister an app principal
within the scope of the target tenancy where the permissions will be
requested. Enabling this capability for an external website to request
permissions on the fly is the primary scenario in which you must
register an app principal with a redirect URL.
For example, imagine that you have developed an ASP.NET website whose base URL is https://appserver.wingtip.com,
and you want this website to be able to request permissions from a
SharePoint site in Office 365 on the fly. First, you need to register
an app principal in the scope of the host tenancy for the SharePoint
site. When registering the app principal you must set the redirect URL
to point to a page in the ASP.NET website such as https://appserver.wingtip.com/RedirectAccept.aspx.
After you have registered the app principal with the proper redirect
URL, the next step involves writing code in the external website to
create the authorization URL. This step is greatly simplified if you
add the TokenHelper class that is also used in the remote web of a cloud-hosted app. The TokenHelper class provides a method named GetAuthorizationUrl.
The code in Example 4 demonstrates how to call the GetAuthorizationUrl
method in an external website. This method accepts three parameters,
including the URL of the host web, the permission being requested (for
example, Web.Read), and a
redirect URL. The redirect URL is important because it is what the
SharePoint host environment uses to call back to the external website
if a user with sufficient permissions grants the permission request.
Example 4. The code required to generate a permission request by using an authorization URL
string urlHostWeb = "https://tenancy01.sharepoint.com/ ";
string urlRedirectAccept = "https://AppServer.wingtip.com/ RedirectAccept.aspx";
string urlAuthorization = TokenHelper.GetAuthorizationUrl(urlHostWeb,
"Web.Read",
urlRedirectAccept);
// redirect
Response.Redirect(urlAuthorization, true);
The GetAuthorizationUrl method parses together a URL that targets a standard SharePoint 2013 application page named OAuthAuthorize.aspx.
The authorization URL also includes query string parameters to pass a
GUID for the client ID, the requested permissions, and the redirect
URL. As shown in Example 5, you can redirect the user to the authorization URL automatically by calling Response.Redirect.
When the user is redirected to the authorization URL within the host
web, the SharePoint host environment responds by displaying a page on
which the user can either grant or deny the permission request. Just as
in the case of a permission request in a SharePoint app, a user must
possess any permissions that are granted in a permission request. If
the user grants the permission request, the SharePoint host environment
responds by passing an authorization code back to the external website by using an HTTP POST operation that targets the page configured as the redirect URL.
Example 5
shows an example of code behind the redirect page that has been written
to retrieve the authorization code and use it to create an access
token. The authorization code is passed from the SharePoint host
environment to the redirect page by using a query string parameter
named code.
Example 5. An external website acquiring an authorization code to access a SharePoint site
string authorizationCode = Request.QueryString["code"];
string targetPrincipalName = "00000003-0000-0ff1-ce00-000000000000"; // Office
365 ID
string targetRealm = "79597708-fc2e-4c79-acfa-710bb435db25"; // tenancy
ID
string urlHostWeb = "https://tenancy01.sharepoint.com/ "; // host web
string urlRedirectAccept = "https://AppServer.wingtip.com/RedirectAccept.aspx";
Uri uriRedirectAccept = new Uri(urlRedirectAccept);
ClientContext context =
TokenHelper.GetClientContextWithAuthorizationCode(urlHostWeb,
targetPrincipalName,
authorizationCode,
targetRealm,
uriRedirectAccept);
context.Load(context.Web);
context.ExecuteQuery();
context.Dispose();
After you have retrieved an authorization code, you can pass it in a call to the GetClientContextWithAuthorizationCode method or an overloaded implementation of the GetAccessToken method. The code in Example 5 demonstrates calling the GetClientContextWithAuthorizationCode
method to create a CSOM client context with an access token that makes
it possible for the website to make CSOM calls on the host web.