Home

Util.AzureCloud / Util.MSAL - can it create credentials for GraphServiceClient ?

I was blown away when I saw LinqPad's ability to simplify MSAL with MFA etc...

Truly great stuff, thanks ! :)

I've tried to create a Graph client using the token generated and I just can't get it right.

Anyone know how I can feed a Util.MSAL token into new GraphServiceClient ?

Thanks

Paul

Comments

  • Have you tried the approach suggested in the LINQPad Tutorial and Reference?

    Using a GraphServiceClient instead of an ArmClient:

    async Task Main()
    {
        string authEndPoint = Util.AzureCloud.PublicCloud.AuthenticationEndpoint;
        string tenantID = "domain.com";
        string userHint = $"user@{tenantID}";
    
        var credential = new LINQPadTokenCredential (authEndPoint + tenantID, userHint);
        var graphServiceClient = new GraphServiceClient (credential);
        ...    
    }
    
    class LINQPadTokenCredential : TokenCredential
    {
        public readonly string Authority, UserIDHint;
    
        public LINQPadTokenCredential (string authority, string userIDHint) => (Authority, UserIDHint) = (authority, userIDHint);
    
        public override AccessToken GetToken (TokenRequestContext requestContext, CancellationToken cancellationToken)
            => GetTokenAsync (requestContext, cancellationToken).Result;
    
        public override async ValueTask<AccessToken> GetTokenAsync (TokenRequestContext requestContext,
                                                                    CancellationToken cancelToken)
        {
            // Call LINQPad's AcquireTokenAsync method to authenticate interactively, and cache token in the LINQPad GUI.
            var auth = await Util.MSAL.AcquireTokenAsync (Authority, requestContext.Scopes, UserIDHint).ConfigureAwait (false);
            return new AccessToken (auth.AccessToken, auth.ExpiresOn);
        }
    }
    
  • Thanks Joe,

    I'm missing something, I'm getting "Access is denied. Check credentials and try again." on the inner exception when using the graph client.
    I think I need to set an App (with a client id) in Azure.
    The outer exception is "Exception of type 'Microsoft.Graph.Models.ODataErrors.ODataError' was thrown."

    After creating the graphServiceClient, I run.... this is where the access denied comes in

    var result = await graphServiceClient.Me.Messages.GetAsync((requestConfiguration) =>
    {
        requestConfiguration.QueryParameters.Filter = "importance eq 'high'";
    }); 
    

    I'm using MFA, could that be the problem? The other example using Util.AzureCloud.PublicCloud works perfectly, but I can't seem to use that token for Microsoft Graph...

    string azureAuth = Util.AzureCloud.PublicCloud.AuthenticationEndpoint;
    string scope = Util.AzureCloud.PublicCloud.ManagementApiDefaultScope;
    
    // Now we can ask the LINQPad host process to authenticate:
    var authResult = await Util.MSAL.AcquireTokenAsync (azureAuth + tenantID, scope, userHint);
    
  • What happens when you try the code I posted?

  • edited July 10

    Hi Joe,

    It throws the exception I mentioned.
    The outer exception is "Exception of type 'Microsoft.Graph.Models.ODataErrors.ODataError' was thrown."
    Main error gives

    • Message: Access is denied. Check credentials and try again.

    I'm using your LINQPadTokenCredential class

    My main method is almost identical to your example, adding the GraphServiceClient...

    async Task Main()
    {
    string authEndPoint = Util.AzureCloud.PublicCloud.AuthenticationEndpoint;
    
    string domain = Util.ReadLine("Enter the domain");
    string username = Util.ReadLine("Enter the username");
    
    string tenantID = domain;
    string userHint = $"{username}@{tenantID}";
    
    var credential = new LINQPadTokenCredential(authEndPoint + tenantID, userHint);
    var graphServiceClient = new GraphServiceClient(credential);
    
    try
    {
        var result = await graphServiceClient.Me.Messages.GetAsync((requestConfiguration) =>
        {
        requestConfiguration.QueryParameters.Filter = "importance eq 'high'";
        });
    }
    catch (Microsoft.Graph.Models.ODataErrors.ODataError ex)
    {
        ex.Dump();
    }
    }
    

    My credentials are good. I know this because if I use your example "Authentication with MSAL (interactive + MFA + Azure + OAuth).linq", and paste the token received into https://jwt.ms, I get a good response.

  • Are you confident that the config on the Azure end is set up correctly to allow these credentials?

  • I should have asked this question a different way, I still have a lot to learn about Azure AD, Auth and Graph

    I can create a GraphServiceClient using a DeviceCodeCredential (Azure.Identity) and setting user scopes. To use this method I also need to register an App in Azure AD. This gives me a clientId and tenantId that I can use when instantiating the GraphServiceClient.

    Using the LinqPad MSAL method, do I need to create the App in Azure Id, and how do I integrate the tenantId, clientId and scopes into the LinqPad MSAL method ?

    My preference is to be able to access the Graph ".Me" methods (ie: userClient.Me.MailFolders["Inbox"].Messages) without needing to register an App in Azure AD, which is what I figured the LinqPad MSAL method gave me.

Sign In or Register to comment.