Adal.js and Azure AD secured web API - Access SharePoint with user context

%3CLINGO-SUB%20id%3D%22lingo-sub-7111%22%20slang%3D%22en-US%22%3EAdal.js%20and%20Azure%20AD%20secured%20web%20API%20-%20Access%20SharePoint%20with%20user%20context%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-7111%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%20class%3D%22remaining-body%22%3EWe%20have%20an%20Azure%20AD%20authenticated%20web%20API.%20We%20successfully%20retrieve%20authentication%20token%20via%20Adal.JS%20and%20authenticate%20against%20the%20web%20API%20controllers%20marked%20with%20Authorize%20attribute.%20However%2C%20we%20would%20like%20for%20some%20controllers%20to%20create%20a%20SharePoint%20user%20context%20with%20the%20TokenHelper%20by%20passing%20the%20authorization%20code.%20We%20are%20receiving%20bad%20request%20error.%20Here%20is%20the%20code%3A%3CBR%20%2F%3E%3CBR%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%3CPRE%3Evar%20authCode%20%3D%20System.Web.HttpContext.Current.Request.Headers%5B%22Authorization%22%5D.Replace(%22Bearer%22%2C%20String.Empty).Trim()%3B%0A%0Avar%20authRealm%20%3D%20TokenHelper.GetRealmFromTargetUrl(new%20Uri(siteCollectionUrl))%3B%0A%0Avar%20redirectUri%20%3D%20new%20Uri(siteCollectionUrl)%3B%0A%0Ausing%20(var%20clientContext%20%3D%0ATokenHelper.GetClientContextWithAuthorizationCode(siteCollectionUrl%2C%20TokenHelper.SharePointPrincipal%2C%20authCode%2C%20authRealm%2C%20redirectUri))...%3C%2FPRE%3E%3CP%3E%3CSPAN%20class%3D%22remaining-body%22%3E%3CBR%20%2F%3EsiteCollectionUrl%20is%20added%20to%20native%20app's%20redirect%20uris%20with%20a%20wildcard%20(we%20also%20tried%20without%20wildcard)%20-%20note%20that%20we%20pass%20it%20as%20a%20part%20of%20the%20redirectUri%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSPAN%20class%3D%22remaining-body%22%3ECurrently%20we%20are%20successfully%20creating%20an%20app%20only%20context%20within%20the%20web%20api%20controllers%20-%20we%20have%20provided%20the%20Azure%20Web%20API%20access%20to%20the%20site%20collection.%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EUpdate%20we%20have%20tried%20the%20following%20approaches%20without%20success%3A%3C%2FP%3E%3CPRE%3Eusing%20(var%20clientContext%20%3D%20new%20OfficeDevPnP.Core.AuthenticationManager().GetAzureADNativeApplicationAuthenticatedContext(siteCollectionUrl%2C%20%22NativeAppClientId%22%2C%20siteCollectionUrl))%3C%2FPRE%3E%3CPRE%3Eusing%20(var%20clientContext%20%3D%20new%20OfficeDevPnP.Core.GetAzureADAccessTokenAuthenticatedContext(siteCollectionUrl%2C%20authCode)%3C%2FPRE%3E%3CP%3EWe%20have%20also%20decoded%20the%20authorization%20code%20to%20its%20JSON%20format%20and%20passed%20the%20pure%20string%20without%20success%20(with%20a%20helper%20classes%20taken%20from%20here%3A%20%3CA%20href%3D%22https%3A%2F%2Fblogs.msdn.microsoft.com%2Fkaevans%2F2013%2F08%2F25%2Fcreating-a-fiddler-extension-for-sharepoint-2013-app-tokens%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fblogs.msdn.microsoft.com%2Fkaevans%2F2013%2F08%2F25%2Fcreating-a-fiddler-extension-for-sharepoint-2013-app-tokens%2F%3C%2FA%3E).%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20have%20added%20access%20to%20the%20native%20app%20to%20SharePoint%20in%20the%20Azure%20AD.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSPAN%20class%3D%22remaining-body%22%3EAnyone%20could%20help%20with%20this%3F%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-7111%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EAPIs%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EDeveloper%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EPnP%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-7388%22%20slang%3D%22en-US%22%3ERe%3A%20Adal.js%20and%20Azure%20AD%20secured%20web%20API%20-%20Access%20SharePoint%20with%20user%20context%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-7388%22%20slang%3D%22en-US%22%3E%3CP%3EOn%20further%20inspection%20we%20have%20noticed%20that%20the%20request%20was%20throwing%20an%20error%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%3E%7Bx-ms-diagnostics%3A%203000003%3Breason%3D%22Invalid%20audience%20Uri%20'Audience%20URI%20as%20specified%20in%20webApiAppIdUri'.%22%3Bcategory%3D%22invalid_client%22%0ASPRequestGuid%3A%2032439d9d-408d-3000-2140-22c0c88730a5%0Arequest-id%3A%2032439d9d-408d-3000-2140-22c0c88730a5%0AStrict-Transport-Security%3A%20max-age%3D31536000%0AX-FRAME-OPTIONS%3A%20SAMEORIGIN%0ASPRequestDuration%3A%2012%0ASPIisLatency%3A%202%0AMicrosoftSharePointTeamServices%3A%2016.0.0.5611%0AX-Content-Type-Options%3A%20nosniff%0AX-MS-InvokeApp%3A%201%3B%20RequireReadOnly%0ADate%3A%20DATE%20IN%20GMT%0AP3P%3A%20CP%3D%22ALL%20IND%20DSP%20COR%20ADM%20CONo%20CUR%20CUSo%20IVAo%20IVDo%20PSA%20PSD%20TAI%20TELo%20OUR%20SAMo%20CNT%20COM%20INT%20NAV%20ONL%20PHY%20PRE%20PUR%20UNI%22%0AServer%3A%20Microsoft-IIS%2F8.5%0AWWW-Authenticate%3A%20Bearer%20realm%3D%22TENANT%20GUID%22%2Cclient_id%3D%2200000003-0000-0ff1-ce00-000000000000%22%2Ctrusted_issuers%3D%2200000001-0000-0000-c000-000000000000%40*%2Chttps%3A%2F%2Fsts.windows.net%2F*%2F%2C00000003-0000-0ff1-ce00-000000000000%4090140122-8516-11e1-8eff-49304924019b%22%2Cauthorization_uri%3D%22https%3A%2F%2Flogin.windows.net%2Fcommon%2Foauth2%2Fauthorize%22%0AX-Powered-By%3A%20ASP.NET%0A%7D%3C%2FPRE%3E%3CP%3EWe%20have%20given%20the%20native%20app%20and%20the%20web%20app%20permissions%20to%20all%20SharePoint%20sites.%3C%2FP%3E%3CP%3EWe%20have%20defined%20the%20endpoints%20object%20in%20the%20ADAL.js%20config%20as%20follows%3A%3C%2FP%3E%3CPRE%3Evar%20endpoints%20%3D%20%7B%7D%3B%0Athis.adalEndPoints%5B_spPageContextInfo.siteAbsoluteUrl%20%2B%20%22%2F_api%2Fweb%2Flists%22%5D%20%3D%20_spPageContextInfo.siteAbsoluteUrl%20%2B%20%22%2F_api%2Fweb%2Flists%22%3B%20%2F%2F%20here%20we%20have%20tried%20different%20permutations%0A...%0A%2F%2F%20ADAL%20endpoints%20for%20automatic%20hooking%0Aendpoints%3A%20%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAnd%20here%20is%20a%20simple%20C%23%20web%20client%20for%20testing%20purposes%20we%20have%20made%3A%3C%2FP%3E%3CPRE%3Estring%20result%20%3D%20String.Empty%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20string%20requestUri%20%3D%20OfficeDevPnP.Core.Utilities.UrlUtility.Combine(siteCollectionUrl%2C%20%22_api%2Fweb%2Flists%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20using%20(var%20httpClient%20%3D%20new%20HttpClient())%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20httpClient.BaseAddress%20%3D%20new%20Uri(siteCollectionUrl)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20httpClient.DefaultRequestHeaders.Accept.Clear()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20httpClient.DefaultRequestHeaders.Accept.Add(new%20System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(%22application%2Fjson%22))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20httpClient.DefaultRequestHeaders.Authorization%20%3D%20new%20System.Net.Http.Headers.AuthenticationHeaderValue(%22Bearer%22%2C%20authToken)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20request%20%3D%20httpClient.GetAsync(requestUri).Result%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20request.EnsureSuccessStatusCode()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(request.StatusCode%20%3D%3D%20System.Net.HttpStatusCode.OK)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20request.Content.ReadAsStringAsync().Result%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20catch(Exception%20ex)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20result%3B%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAnybody%20could%20point%20me%20to%20a%20solution%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E
Contributor

We have an Azure AD authenticated web API. We successfully retrieve authentication token via Adal.JS and authenticate against the web API controllers marked with Authorize attribute. However, we would like for some controllers to create a SharePoint user context with the TokenHelper by passing the authorization code. We are receiving bad request error. Here is the code:

var authCode = System.Web.HttpContext.Current.Request.Headers["Authorization"].Replace("Bearer", String.Empty).Trim();

var authRealm = TokenHelper.GetRealmFromTargetUrl(new Uri(siteCollectionUrl));

var redirectUri = new Uri(siteCollectionUrl);

using (var clientContext =
TokenHelper.GetClientContextWithAuthorizationCode(siteCollectionUrl, TokenHelper.SharePointPrincipal, authCode, authRealm, redirectUri))...


siteCollectionUrl is added to native app's redirect uris with a wildcard (we also tried without wildcard) - note that we pass it as a part of the redirectUri

 

Currently we are successfully creating an app only context within the web api controllers - we have provided the Azure Web API access to the site collection.

 

Update we have tried the following approaches without success:

using (var clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetAzureADNativeApplicationAuthenticatedContext(siteCollectionUrl, "NativeAppClientId", siteCollectionUrl))
using (var clientContext = new OfficeDevPnP.Core.GetAzureADAccessTokenAuthenticatedContext(siteCollectionUrl, authCode)

We have also decoded the authorization code to its JSON format and passed the pure string without success (with a helper classes taken from here: https://blogs.msdn.microsoft.com/kaevans/2013/08/25/creating-a-fiddler-extension-for-sharepoint-2013...).

 

We have added access to the native app to SharePoint in the Azure AD.

 

Anyone could help with this?

1 Reply

On further inspection we have noticed that the request was throwing an error

 

{x-ms-diagnostics: 3000003;reason="Invalid audience Uri 'Audience URI as specified in webApiAppIdUri'.";category="invalid_client"
SPRequestGuid: 32439d9d-408d-3000-2140-22c0c88730a5
request-id: 32439d9d-408d-3000-2140-22c0c88730a5
Strict-Transport-Security: max-age=31536000
X-FRAME-OPTIONS: SAMEORIGIN
SPRequestDuration: 12
SPIisLatency: 2
MicrosoftSharePointTeamServices: 16.0.0.5611
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: DATE IN GMT
P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
Server: Microsoft-IIS/8.5
WWW-Authenticate: Bearer realm="TENANT GUID",client_id="00000003-0000-0ff1-ce00-000000000000",trusted_issuers="00000001-0000-0000-c000-000000000000@*,https://sts.windows.net/*/,00000003-0000-0ff1-ce00-000000000000@90140122-8516-11e1-8eff-49304924019b",authorization_uri="https://login.windows.net/common/oauth2/authorize"
X-Powered-By: ASP.NET
}

We have given the native app and the web app permissions to all SharePoint sites.

We have defined the endpoints object in the ADAL.js config as follows:

var endpoints = {};
this.adalEndPoints[_spPageContextInfo.siteAbsoluteUrl + "/_api/web/lists"] = _spPageContextInfo.siteAbsoluteUrl + "/_api/web/lists"; // here we have tried different permutations
...
// ADAL endpoints for automatic hooking
endpoints: 

 

And here is a simple C# web client for testing purposes we have made:

string result = String.Empty;
            string requestUri = OfficeDevPnP.Core.Utilities.UrlUtility.Combine(siteCollectionUrl, "_api/web/lists");
            try
            {
                using (var httpClient = new HttpClient())
                {
                    httpClient.BaseAddress = new Uri(siteCollectionUrl);
                    httpClient.DefaultRequestHeaders.Accept.Clear();
                    httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                    httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);

                    var request = httpClient.GetAsync(requestUri).Result;
                    request.EnsureSuccessStatusCode();
                    if (request.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        result = request.Content.ReadAsStringAsync().Result;
                    }
                }
            }
            catch(Exception ex)
            {

            }

            return result;

 

Anybody could point me to a solution?