microsoftgraph / msgraph-sdk-dotnet-auth

Archived - use the TokenCredential classes provided by Azure.Identity. https://docs.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme
https://graph.microsoft.com
MIT License
78 stars 19 forks source link

How to reuse access tokens? Now each action requires two requests (login.microsoftonline.com, graph.microsoft.com) #34

Closed Misiu closed 5 years ago

Misiu commented 5 years ago

I've built a simple POC application that allows me to send email on behalf of the user from Windows Service.

I'm sending mail using this code:

var recipientList = new List<Recipient>
{
    new Recipient {EmailAddress = new Microsoft.Graph.EmailAddress {Address = "demo@example.com"}}
};

var email = new Message
{
    Body = new ItemBody
    {
        Content = "Works fine!",
        ContentType = BodyType.Html,
    },
    Subject = "Test",
    ToRecipients = recipientList
};
await graphClient.Users["test@example.onmicrosoft.com"].SendMail(email, true).Request().WithMaxRetry(5).PostAsync();

I've build my GraphServiceClient like so:

var clientCredential = new ClientCredential(clientSecret);
IConfidentialClientApplication clientApplication = AuthorizationCodeProvider.CreateClientApplication(clientId, "https://daemon", clientCredential, null, tenant);
IAuthenticationProvider authenticationProvider = new ClientCredentialProvider(clientApplication);
IGraphServiceClient graphClient = new GraphServiceClient("https://graph.microsoft.com/v1.0", authenticationProvider);

When I call above code I've noticed that sending email requires two requests: first to login.microsoftonline.com second to graph.microsoft.com

This is correct, but when I want to send 5 emails there should be only 6 requests, but I see 10 in fiddler.

For testing porpuse I use simple for to send multiple emails:

for (int j = 0; j < max; j++)
{
    await graphClient.Users["test@example.onmicrosoft.com"].SendMail(email, true).Request().WithMaxRetry(5).PostAsync();
}

is this because of passing null to CreateClientApplication?

I've tried creating custom class that implements ITokenStorageProvider but that didn't solve the problem.

Is this a bug of is it by design?

peombwa commented 5 years ago

@Misiu This is because you are using AuthorizationCodeProvider.CreateClientApplication which creates a ConfidentialClientApplication configured for an AuthorizationCodeProvider and not ClientCredentialProvider - it internally sets a user token cache and not an app token cache that ClientCredentialProvider expects.

When using a ClientCredentialProvider, you should use ClientCredentialProvider.CreateClientApplication to create a ConfidentialClientApplication. Note that ClientCredentialProvider.CreateClientApplication currently has an open issue #25 and a workaround has been documented here. We will release a fix for this issue in our next release which should be out in a couple of days.

Misiu commented 5 years ago

@pwombwa thank You for clarification. I've changed my code to:

IConfidentialClientApplication clientApplication = new ConfidentialClientApplication(clientId, "https://daemon", clientCredential, null, new TokenCache());
IAuthenticationProvider authenticationProvider = new ClientCredentialProvider(clientApplication);
IGraphServiceClient graphClient = new GraphServiceClient("https://graph.microsoft.com/v1.0", authenticationProvider);

but now when I try to send mail I get this error:

Code: NoPermissionsInAccessToken Message: The token contains no permissions, or permissions can not be understood.

EDIT1: The key was the authority parameter of ConfidentialClientApplication I had to build it like so:

const string tenant = "1c...b7";
const string azureAdInstance = "https://login.microsoftonline.com/{0}";
var authority = string.Format(CultureInfo.InvariantCulture, azureAdInstance, tenant);

and then use it like this:

var clientApplication = new ConfidentialClientApplication(clientId, authority, "https://daemon", clientCredential, null, new TokenCache());

hope this help others having same problem 😉

EDIT2 ClientCredentialProvider.CreateClientApplication works fine in 0.1.0-preview.2.

peombwa commented 5 years ago

@Misiu Great! I'll now close this issue.