Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Microsoft Graph GraphServiceClient with user/password unattended

I am creating a console application that connects to Microsoft Graph using the Microsoft Graph API (as shown in https://github.com/microsoftgraph/console-csharp-connect-sample). Everything is working fine, but I wonder if there is a way where I can authenticate a user (when I already know their user/password) without them needing to manually enter their credentials on the "Sing in to your account" window rendered on the desktop. The idea is basically to run the application unattended, so there is no need for the user to be entering their credentials when the application starts. I can´t find any relevant information on the subject. Is that even possible?

EDIT

After following the link @DanSilver posted about geting access without a user, I tried the sample suggested in that link (https://github.com/Azure-Samples/active-directory-dotnet-daemon-v2). Although that is an MVC application that forces users to authenticate (precisely what I wanted to avoid) I have managed to use part of the authentication code in that sample with my console application. After giving authorization to the application manually through a request to https://login.microsoftonline.com/myTenantId/adminconsent I can create a GraphServiceClient in my console app that connects to Graph without user interaction. So I mark the answer as valid. Just in case someone is in the same situation, the GraphServiceclient is created as:

GraphServiceClient graphServiceClientApplication = new GraphServiceClient("https://graph.microsoft.com/v1.0", new DelegateAuthenticationProvider(
    async (requestMessage) =>
    {
        string clientId = "yourClientApplicationId";
        string authorityFormat = "https://login.microsoftonline.com/{0}/v2.0";
        string tenantId = "yourTenantId";
        string msGraphScope = "https://graph.microsoft.com/.default";
        string redirectUri = "msalXXXXXX://auth"; // Custom Redirect URI asigned in the Application Registration Portal in the native Application Platform
        string clientSecret = "passwordGenerated"; 
        ConfidentialClientApplication daemonClient = new ConfidentialClientApplication(clientId, String.Format(authorityFormat, tenantId), redirectUri, new ClientCredential(clientSecret), null, new TokenCache());
        AuthenticationResult authResult = await daemonClient.AcquireTokenForClientAsync(new string[] { msGraphScope });
        string token = authResult.AccessToken;
        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);                            
    }                
));
like image 463
Ada Avatar asked Jan 15 '18 17:01

Ada


People also ask

Which type of applications can access Microsoft Graph without a user?

Supported app scenarios and resourcesBackground services (daemons) that run on a server without a signed-in user. Apps that have a signed-in user but also call Microsoft Graph with their own identity. For example, to use functionality that requires more elevated privileges than the user has.

Does Microsoft Graph use OAuth?

Your app can use this token to call Microsoft Graph. An OAuth 2.0 refresh token. Your app can use this token to acquire additional access tokens after the current access token expires.


1 Answers

I did want to come back out here and share, since I ran into this problem yesterday, and the idea of granting read/write mailbox access for my application... to EVERYONE'S EMAIL BOX IN THE ENTIRE ORGANIZATION... was way over the top for my needs. (And that is exactly what happens when you start talking about granting Application level permissions instead of delegated permissions to your registered app).

It's a simple use case: I had a nightly process that needed to automate sending of emails from a shared mailbox using a traditional AD service account.

Thankfully... even though they are on the march to eliminate passwords (lol)... someone at Microsoft still recognizes my use case, and it's lack of apples-to-apples alternatives in Azure AD. There is still an extension method we can lean on to get the job done:

private AuthenticationContext authContext = null;
authContext = new AuthenticationContext("https://login.microsoftonline.com/ourmail.onmicrosoft.com", 
                new TokenCache());
result = authContext.AcquireTokenAsync("https://graph.microsoft.com/", 
                "12345678-1234-1234-1234-1234567890", 
                new UserPasswordCredential( 
                    Environment.GetEnvironmentVariable("UID", EnvironmentVariableTarget.User), 
                    Environment.GetEnvironmentVariable("UPD", EnvironmentVariableTarget.User) 
                )).Result;    

You can replace those GetEnvironmentVariable calls with your Username (UID) and Password (UPD). I just stuff them in the environment variables of the service account so I didn't have to check anything into source control.

AcquireTokenAsync is an extension method made available from the Microsoft.IdentityModel.Clients.ActiveDirectory namespace. From there, it's a simple business to fire up a GraphClient.

        string sToken = result.AccessToken;
        Microsoft.Graph.GraphServiceClient oGraphClient = new GraphServiceClient(
                    new DelegateAuthenticationProvider((requestMessage) => {
                        requestMessage
                            .Headers
                            .Authorization = new AuthenticationHeaderValue("bearer", sToken);
            return Task.FromResult(0);
        }));

The last bit of magic was to add these permissions to Application registration I created in Azure AD (where that GUID came from). The application has be defined as a Public client (there's a radio button for that towards the bottom of the authentication tab). I added the following 5 DELEGATED permissions (NOT application permissions):

Microsoft Graph
1. Mail.ReadWrite.Shared
2. Mail.Send.Shared
3. User.Read
4. email
5. openid

Since user consents are actually blocked in our organization, another permissions admin had to review my application definition and then do an admin level grant of those rights, but once he did, everything lit up and worked like I needed: limited access by a service account to a single shared mailbox, with the actual security of that access being managed in Office 365 and not Azure AD.

like image 167
Frog Pr1nce Avatar answered Sep 27 '22 21:09

Frog Pr1nce