Reputation: 756
I have developed an Office.js Word add-in and I am using the SSO feature as described here. It uses the Office.Auth interface
method getAccessTokenAsync
, shown here. This works as described, but the issue comes when I try to use more scopes to access SharePoint using Microsoft Graph.
TL;DR
I am unable to successfully make Microsoft Graph calls to access SharePoint with the token generated from the Office.Auth interface getAccessTokenAsync
method.
Full Description
I have done the following:
Sites.ReadWrite.All
and Sites.Manage.All
permissions in
the Azure AD app registration. Added the additional scopes in the Word Add-in manifest.
<WebApplicationInfo>
<Id>$application_GUID here$</Id>
<Resource>api://localhost:44355/$application_GUID here$</Resource>
<Scopes>
<Scope>Files.Read.All</Scope>
<Scope>Sites.ReadWrite.All</Scope>
<Scope>Sites.Manage.All</Scope>
<Scope>offline_access</Scope>
<Scope>openid</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
Confirmed using Graph Explorer that I can make the SharePoint Graph calls, as my user.
GET https://graph.microsoft.com/v1.0/sites/{site-id}/lists/{list-id}/items/{item-id}
Added the additional scopes in the Authorize
method for when the user is not logged into Word, as described here.
ConfidentialClientApplicationBuilder clientBuilder = ConfidentialClientApplicationBuilder.Create(Settings.AzureADClientId);
clientBuilder.WithClientSecret(Settings.AzureADClientSecret);
clientBuilder.WithRedirectUri(loginRedirectUri.ToString());
clientBuilder.WithAuthority(Settings.AzureADAuthority);
ConfidentialClientApplication clientApp = (ConfidentialClientApplication) clientBuilder.Build();
string[] graphScopes = { "Files.Read.All", "User.Read", "Sites.ReadWrite.All", "Sites.Manage.All" };
// Get and save the token.
var authResultBuilder = clientApp.AcquireTokenByAuthorizationCode(
graphScopes,
Request.Params["code"] // The auth 'code' parameter from the Azure redirect.
);
try
{
var authResult = await authResultBuilder.ExecuteAsync();
ViewBag.AccessToken = authResult.AccessToken;
}
catch (Exception e)
{
ViewBag.Error = e.Message;
}
return View();
What Works
When the user is not logged into Word and has to call the Authorize
method, I am able to use the returned token to successfully make my Graph calls.
What does not Work
When the user is already logged into Word and the add-in JS generates the token using the getAccessTokenAsync
method, I get 'Unauthorized' when trying to make the same Graph calls using the returned
Question
Is there something extra I need to do for the Office JS getAccessTokenAsync
method to return an authorized token for use with my Graph calls to SharePoint?
Edit Post Further Investigation
I used jwt.io to decode the tokens received.
getAccessTokenAsync
method when logged in
(scenario that does not work), I get a token containing the
following: {
"aud": $application_GUID$,
"iss": "https://login.microsoftonline.com/$tenant_GUID$/v2.0",
"iat": ...,
"nbf": ...,
"exp": ...,
"aio": ...,
"azp": ...,
"azpacr": "0",
"name": $user_full_name$,
"oid": $GUID$,
"preferred_username": $user_email$,
"scp": "access_as_user",
"sub": ...,
"tid": $tenant_GUID$,
"uti": ...,
"ver": "2.0"
}
getAccessToken
method, both when logged
in and prompted to log in, (scenarios that also do not work), I
get a token containing the same as above. getAccessTokenAsync
method, when prompted to log in and taken to
theAzureADAuthController
, (scenario that does work!), I get a
token containing the following:{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/$tenant_GUID$/",
"iat": ...,
"nbf": ...,
"exp": ...,
"acct": 0,
"acr": "1",
"aio": ...,
"amr": [
"pwd"
],
"app_displayname": "Office-Add-in-ASPNET-SSO",
"appid": $application_GUID$,
"appidacr": "1",
"deviceid": $GUID$,
"family_name": $user_last_name$,
"given_name": $user_first_name$,
"ipaddr": ...,
"name": $user_full_name$,
"oid": $GUID$,
"platf": "3",
"puid": ...,
"scp": "Files.Read.All openid profile Sites.Manage.All Sites.ReadWrite.All User.Read email",
"sub": ...,
"tid": $tenant_GUID$,
"unique_name": $user_email$,
"upn": $user_email$,
"uti": ...,
"ver": "1.0",
"xms_st": {
"sub": ...
},
"xms_tcdt": ...
}
Notice the difference in scopes, where the latter, older version has fully listed scopes, and I am able to authorize this way.
What could explain this?
Upvotes: 2
Views: 748
Reputation: 9674
Not much of an answer, but too long to put in a comment:
That sample changed recently to use the new OfficeRuntime.auth.getAccessToken
. You seem to be using an older version that uses Office.auth.getAccessTokenAsync
. That should still work, but it was a preview API and may stop working at some point. Consider cloning the newer version. But wait a few days. I'm about to push some fixes to the new version.
Check to see if you've also added the new scopes to the graphScopes
array in the Login action method. (In addition to adding them to the Authorize action method as you've already done.)
Exactly which HTTP call is returning the "Unauthorized"?
What error is being retuned from getAccessToken
(or getAccessTokenAsync
)? It usually has a 13xxx number.
UPDATE 12/19/19:
Based on your description in your comment "To clarify...", it looks like you are including the token that you get from getAccessToken
in your call to MS Graph. This will not work. That token is a "bootstrap token". It gives Office access to your add-in's web app. The web app then needs to use the On Behalf Of Flow to swap that token for a token that gives the web app access to MS Graph. You then include this second token as the Authorization header in the call to Graph. The sample that you linked to in the first sentence of your question does that. Please also see these articles:
Finally, be sure that there is a blank space between the string "Bearer" and the token in the Authorization header.
Upvotes: 2