App + User authentication and Project Online development

Published Nov 23 2020 02:43 PM 5,603 Views
Frequent Contributor

With the most recent updates to the SharePoint client object model (CSOM) libraries it is now possible to authenticate to SharePoint and Project Online with the MSAL libraries rather than ADAL - and this opens up the use of .NET Standard rather than needing the .NET Framework.  This DOES NOT however mean that Project Online supports App ID only authentication.  SharePoint Online does support app only - but the additional authorisation level in Project to understand who the user is and what they can do requires app + user.  See more information here - https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/using-csom-for-dotnet-standard and the API permissions you can choose are shown here. Im my example I've just selecting the Project.Write which allows me to create and update a project.

 

API Permission Options for Project OnlineAPI Permission Options for Project Online

You application would need to reference the Application (Client) ID associated with these permissions when requesting token - but would also need to pass in the credentials of a user with permissions and license to Project Online.  This could be an interactive login - or using a securely stored username and password (not recommended) or using a stored token that is refreshed periodically.  Attempting to connect by with the application ID will fail with an "unauthorized" response.

 

As an example, the following code would get the token and set for project context to make further CSOM calls: 

 

 

            string domainName = "brismith.onmicrosoft.com";
            string PJOAccount = "brismith@brismith.onmicrosoft.com";
            string scope = "https://brismith.sharepoint.com/Project.Write";
            string redirectUri = "http://localhost";
            string pwaInstanceUrl = "https://brismith.sharepoint.com/sites/pwa/";         // your pwa url
            int DEFAULTTIMEOUTSECONDS = 300;
            

            HttpClient Client = new HttpClient();
            var TenantId = ((dynamic)JsonConvert.DeserializeObject(Client.GetAsync("https://login.microsoftonline.com/" + domainName + "/v2.0/.well-known/openid-configuration")
                .Result.Content.ReadAsStringAsync().Result))
                .authorization_endpoint.ToString().Split('/')[3];

            // This client ID just has project.write
            PublicClientApplicationBuilder pcaConfig = PublicClientApplicationBuilder.Create("87edf46a-466d-4241-8afc-b9650d7fb0d7")
            .WithTenantId(TenantId);

            pcaConfig.WithRedirectUri(redirectUri);

            // This section uses the interactive flow for auth
            var TokenResult = pcaConfig.Build().AcquireTokenInteractive(new[] { scope })
                .WithPrompt(Prompt.NoPrompt)
                .WithLoginHint(PJOAccount).ExecuteAsync().Result;


            //The following section uses the username and password - this would be best pulled from Azure Key Vault or use another auth flow
            //This also requires the app registration to be set as a public client
            //SampleConfiguration config = SampleConfiguration.ReadFromJsonFile("appsettings.json");
            //string text1 = config.Text1;
            //var sc = new SecureString();
            //foreach (char c in text1) sc.AppendChar(c);

            //var TokenResult = pcaConfig.Build().AcquireTokenByUsernamePassword(new[] { scope }, PJOAccount, sc).ExecuteAsync().Result;

            // Load ps context
            csom.ProjectContext psCtx = new csom.ProjectContext(pwaInstanceUrl);
            psCtx.ExecutingWebRequest += (s, e) =>
            {
                e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + TokenResult.AccessToken;
            };

 

- using the latest MSAL (Microsoft.Identity.Client v4.22) and Microsoft.ProjectServer.Client from Microsoft.SharePointOnline.CSOM 16.1.20616.12000 at the time of writing.  These will also work with legacy auth disabled which is a setting that may break some existing custom applications.

 

To check if legacy auth is disabled you can open the SharePoint Online Management shell, connect to your admin Url and run Get-SPOTenent.  Look in the returned properties for:

 

LegacyAuthProtocolsEnabled : False

 

which in my case shows that legacy auth is disabled.

 

Hopefully we will get the sample on Github updated with this latest information.

 

 

17 Comments
%3CLINGO-SUB%20id%3D%22lingo-sub-1925443%22%20slang%3D%22en-US%22%3EApp%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1925443%22%20slang%3D%22en-US%22%3E%3CP%3EWith%20the%20most%20recent%20updates%20to%20the%20SharePoint%20client%20object%20model%20(CSOM)%20libraries%20it%20is%20now%20possible%20to%20authenticate%20to%20SharePoint%20and%20Project%20Online%20with%20the%20MSAL%20libraries%20rather%20than%20ADAL%20-%20and%20this%20opens%20up%20the%20use%20of%20.NET%20Standard%20rather%20than%20needing%20the%20.NET%20Framework.%26nbsp%3B%20This%20DOES%20NOT%20however%20mean%20that%20Project%20Online%20supports%20App%20ID%20only%20authentication.%26nbsp%3B%20SharePoint%20Online%20does%20support%20app%20only%20-%20but%20the%20additional%20authorisation%20level%20in%20Project%20to%20understand%20who%20the%20user%20is%20and%20what%20they%20can%20do%20requires%20app%20%2B%20user.%26nbsp%3B%20See%20more%20information%20here%20-%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fsharepoint%2Fdev%2Fsp-add-ins%2Fusing-csom-for-dotnet-standard%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fsharepoint%2Fdev%2Fsp-add-ins%2Fusing-csom-for-dotnet-standard%3C%2FA%3E%26nbsp%3Band%20the%20API%20permissions%20you%20can%20choose%20are%20shown%20here.%20Im%20my%20example%20I've%20just%20selecting%20the%20Project.Write%20which%20allows%20me%20to%20create%20and%20update%20a%20project.%3C%2FP%3E%3CDIV%20class%3D%22mceNonEditable%20lia-copypaste-placeholder%22%3E%26nbsp%3B%3C%2FDIV%3E%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22PJOAPIPermissions.png%22%20style%3D%22width%3A%20907px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F235677i002EF4CD29D99BAB%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22PJOAPIPermissions.png%22%20alt%3D%22API%20Permission%20Options%20for%20Project%20Online%22%20%2F%3E%3CSPAN%20class%3D%22lia-inline-image-caption%22%20onclick%3D%22event.preventDefault()%3B%22%3EAPI%20Permission%20Options%20for%20Project%20Online%3C%2FSPAN%3E%3C%2FSPAN%3E%3C%2FP%3E%3CP%3EYou%20application%20would%20need%20to%20reference%20the%20Application%20(Client)%20ID%20associated%20with%20these%20permissions%20when%20requesting%20token%20-%20but%20would%20also%20need%20to%20pass%20in%20the%20credentials%20of%20a%20user%20with%20permissions%20and%20license%20to%20Project%20Online.%26nbsp%3B%20This%20could%20be%20an%20interactive%20login%20-%20or%20using%20a%20securely%20stored%20username%20and%20password%20(not%20recommended)%20or%20using%20a%20stored%20token%20that%20is%20refreshed%20periodically.%26nbsp%3B%20Attempting%20to%20connect%20by%20with%20the%20application%20ID%20will%20fail%20with%20an%20%22unauthorized%22%20response.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAs%20an%20example%2C%20the%20following%20code%20would%20get%20the%20token%20and%20set%20for%20project%20context%20to%20make%20further%20CSOM%20calls%3A%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%20%20%20%20%20%20%20%20%20%20%20%20string%20domainName%20%3D%20%22brismith.onmicrosoft.com%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20string%20PJOAccount%20%3D%20%22brismith%40brismith.onmicrosoft.com%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20string%20scope%20%3D%20%22https%3A%2F%2Fbrismith.sharepoint.com%2FProject.Write%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20string%20redirectUri%20%3D%20%22http%3A%2F%2Flocalhost%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20string%20pwaInstanceUrl%20%3D%20%22https%3A%2F%2Fbrismith.sharepoint.com%2Fsites%2Fpwa%2F%22%3B%20%20%20%20%20%20%20%20%20%2F%2F%20your%20pwa%20url%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20DEFAULTTIMEOUTSECONDS%20%3D%20300%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20HttpClient%20Client%20%3D%20new%20HttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20TenantId%20%3D%20((dynamic)JsonConvert.DeserializeObject(Client.GetAsync(%22https%3A%2F%2Flogin.microsoftonline.com%2F%22%20%2B%20domainName%20%2B%20%22%2Fv2.0%2F.well-known%2Fopenid-configuration%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Result.Content.ReadAsStringAsync().Result))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.authorization_endpoint.ToString().Split('%2F')%5B3%5D%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20This%20client%20ID%20just%20has%20project.write%0A%20%20%20%20%20%20%20%20%20%20%20%20PublicClientApplicationBuilder%20pcaConfig%20%3D%20PublicClientApplicationBuilder.Create(%2287edf46a-466d-4241-8afc-b9650d7fb0d7%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.WithTenantId(TenantId)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20pcaConfig.WithRedirectUri(redirectUri)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20This%20section%20uses%20the%20interactive%20flow%20for%20auth%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20TokenResult%20%3D%20pcaConfig.Build().AcquireTokenInteractive(new%5B%5D%20%7B%20scope%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.WithPrompt(Prompt.NoPrompt)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.WithLoginHint(PJOAccount).ExecuteAsync().Result%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FThe%20following%20section%20uses%20the%20username%20and%20password%20-%20this%20would%20be%20best%20pulled%20from%20Azure%20Key%20Vault%20or%20use%20another%20auth%20flow%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FThis%20also%20requires%20the%20app%20registration%20to%20be%20set%20as%20a%20public%20client%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FSampleConfiguration%20config%20%3D%20SampleConfiguration.ReadFromJsonFile(%22appsettings.json%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fstring%20text1%20%3D%20config.Text1%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fvar%20sc%20%3D%20new%20SecureString()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fforeach%20(char%20c%20in%20text1)%20sc.AppendChar(c)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fvar%20TokenResult%20%3D%20pcaConfig.Build().AcquireTokenByUsernamePassword(new%5B%5D%20%7B%20scope%20%7D%2C%20PJOAccount%2C%20sc).ExecuteAsync().Result%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Load%20ps%20context%0A%20%20%20%20%20%20%20%20%20%20%20%20csom.ProjectContext%20psCtx%20%3D%20new%20csom.ProjectContext(pwaInstanceUrl)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20psCtx.ExecutingWebRequest%20%2B%3D%20(s%2C%20e)%20%3D%26gt%3B%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%20e.WebRequestExecutor.RequestHeaders%5B%22Authorization%22%5D%20%3D%20%22Bearer%20%22%20%2B%20TokenResult.AccessToken%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%3B%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E-%20using%20the%20latest%20MSAL%20(Microsoft.Identity.Client%20v4.22)%20and%20Microsoft.ProjectServer.Client%20from%20Microsoft.SharePointOnline.CSOM%2016.1.20616.12000%20at%20the%20time%20of%20writing.%26nbsp%3B%20These%20will%20also%20work%20with%20legacy%20auth%20disabled%20which%20is%20a%20setting%20that%20may%20break%20some%20existing%20custom%20applications.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20check%20if%20legacy%20auth%20is%20disabled%20you%20can%20open%20the%20SharePoint%20Online%20Management%20shell%2C%20connect%20to%20your%20admin%20Url%20and%20run%20Get-SPOTenent.%26nbsp%3B%20Look%20in%20the%20returned%20properties%20for%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%20class%3D%22lia-indent-padding-left-30px%22%3ELegacyAuthProtocolsEnabled%20%3A%20False%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3Ewhich%20in%20my%20case%20shows%20that%20legacy%20auth%20is%20disabled.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHopefully%20we%20will%20get%20the%20sample%20on%20Github%20updated%20with%20this%20latest%20information.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-1925443%22%20slang%3D%22en-US%22%3E%3CP%3EWith%20the%20most%20recent%20updates%20to%20the%20SharePoint%20client%20object%20model%20(CSOM)%20libraries%20it%20is%20now%20possible%20to%20authenticate%20to%20SharePoint%20and%20Project%20Online%20with%20the%20MSAL%20libraries%20rather%20than%20ADAL%20-%20and%20this%20opens%20up%20the%20use%20of%20.NET%20Standard%20rather%20than%20needing%20the%20.NET%20Framework.%26nbsp%3B%20This%20DOES%20NOT%20however%20mean%20that%20Project%20Online%20supports%20App%20ID%20only%20authentication.%20Read%20on...%3C%2FP%3E%3C%2FLINGO-TEASER%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1926181%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1926181%22%20slang%3D%22en-US%22%3E%3CP%3EHi%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F68%22%20target%3D%22_blank%22%3E%40Brian%20Smith%3C%2FA%3E%2C%3C%2FP%3E%3CP%3EDo%20you%20know%20if%20there%20has%20been%20also%20new%20API%20functionality%20added%20to%20Project%20CSOM%2C%20e.g.%20set%20a%20baseline%3F%3C%2FP%3E%3CP%3EWill%20there%20be%20an%20updated%20API%20documentation%20in%20the%20future%3F%20The%20current%20one%20is%20still%20for%20Project%20Server%202013.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1927255%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1927255%22%20slang%3D%22en-US%22%3E%3CP%3ENo%20changes%20to%20CSOM%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F2087%22%20target%3D%22_blank%22%3E%40Trutz%20Stephani%3C%2FA%3E%26nbsp%3B-%20there%20was%20a%20recent%20REST%20change%20to%20allow%20task%20level%20custom%20fields%20to%20be%20edited%20-%20but%20nothing%20new%20likely%20for%20CSOM.%26nbsp%3B%20Likewise%20the%20samples%20will%20hopefully%20get%20updated%20at%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FOfficeDev%2FProject-Samples%2F%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EGitHub%20-%20OfficeDev%2FProject-Samples%3A%3C%2FA%3E%26nbsp%3B-%20but%20the%202013%20documentation%20is%20still%20pretty%20much%20accurate.%26nbsp%3B%20I'll%20check%20with%20the%20product%20group%20-%20as%20it%20would%20be%20useful%20to%20at%20least%20update%20the%20document%20with%20this%20new%20.NET%20Standard%20capability.%3C%2FP%3E%3CP%3EBest%20regards%2C%3C%2FP%3E%3CP%3EBrian%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1953404%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1953404%22%20slang%3D%22en-US%22%3E%3CP%3EHi%2C%20I'm%20getting...%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20request%20body%20must%20contain%20the%20following%20parameter%3A%20'client_assertion'%20or%20'client_secret'.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAny%20ideas%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1956662%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1956662%22%20slang%3D%22en-US%22%3E%3CP%3EI've%20seen%20that%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F887112%22%20target%3D%22_blank%22%3E%40Hepster%3C%2FA%3E%20but%20don't%20recall%20what%20I'd%20done%20wrong%20when%20that%20appeared%26nbsp%3B%20-%20possibly%20you%20haven't%20set%20the%20API%20with%20the%20public%20client%20option%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1976376%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1976376%22%20slang%3D%22en-US%22%3E%3CP%3EGot%20it%20working%20now%20-%20cheers.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2023910%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2023910%22%20slang%3D%22en-US%22%3E%3CP%3EAny%20idea%20on%2C%20how%20to%20achieve%20authentication%20in%20case%20of%20SSIS%20Package%20%3F%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2023911%22%20slang%3D%22en-US%22%3ERe%3A%20App%20%2B%20User%20authentication%20and%20Project%20Online%20development%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2023911%22%20slang%3D%22en-US%22%3E%3CP%3EIs%20above%20screenshot%20%22%3CEM%3ERequest%20API%20Permission%3C%2FEM%3E%22%20from%20the%20azure%20App%20registration%20section%20%3F%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E
Version history
Last update:
‎Nov 23 2020 02:43 PM
Updated by:
www.000webhost.com