Retrieving a persistent token for Azure user access

Viewed 87

I’m working on a project where I need access to a users mailbox (similar to how the MS Flow mailbox connector works), this is fine for when the user is on the site as I can access their mailbox from the graph and the correct permissions request. The problem I have is I need a web job to continually monitor that users mail folder after they’ve given permission. I know that I can use an Application request rather than a delegate request but I doubt my company will sign this off. Is there a way to persistently hold an azure token to access the user information after a user has left the site.. e.g. in a webjob?

Edit

Maybe I've misjudged this, the user authenticates in a web application against an Azure Application for the requested scope

let mailApp : PublicClientApplication = new PublicClientApplication(msalAppConfig);
      let mailUser = mailApp.getAllAccounts()[0];
      let accessTokenRequest = {
        scopes : [ "User.Read", "MailboxSettings.Read", "Mail.ReadWrite", "offline_access" ],
        account : mailUser,
      }
      mailApp.acquireTokenPopup(accessTokenRequest).then(accessTokenResponse => {
.....
}

This returns the correct response as authenticated.

I then want to use this users authentication in a Console App / Web Job, which I try to do with

var app = ConfidentialClientApplicationBuilder.Create(ClientId)
                                          .WithClientSecret(Secret)
                                          .WithAuthority(Authority, true)
                                          .WithTenantId(Tenant)
                                          .Build();

                System.Threading.Tasks.Task.Run(async () =>
                {
                    IAccount test = await app.GetAccountAsync(AccountId);
                }).Wait();

But the GetAccountAsync allways comes back as null?

2 Answers

@juunas was correct that the tokens are refreshed as needed and to use the AcquireTokenOnBehalfOf function. He should be credited with the answer if possible?

With my code, the idToken returned can be used anywhere else to access the resources. Since my backend WebJob is continuous, I can use the the stored token to access the resource and refresh the token on regular intervals before it expires.

Angalar App:

let mailApp : PublicClientApplication = new PublicClientApplication(msalAppConfig);
let mailUser = mailApp.getAllAccounts()[0];
let accessTokenRequest = {
    scopes : [ "User.Read", "MailboxSettings.Read", "Mail.ReadWrite", "offline_access" ],
    account : mailUser,
}
mailApp.acquireTokenPopup(accessTokenRequest).then(accessTokenResponse => {
    let token : string = accessTokenResponse.idToken;
}

On the backend, either in an API, webJob or Console:

var app = ConfidentialClientApplicationBuilder.Create(ClientId)
                                                      .WithClientSecret(Secret)
                                                      .WithAuthority(Authority, true)
                                                      .WithTenantId(Tenant)
                                                      .Build();
            
var authProvider = new DelegateAuthenticationProvider(async (request) => {
   // Use Microsoft.Identity.Client to retrieve token
   List<string> scopes = new List<string>() { "Mail.ReadWrite", "MailboxSettings.Read", "offline_access", "User.Read" };
   var assertion = new UserAssertion(YourPreviouslyStoredToken);
   var result = await app.AcquireTokenOnBehalfOf(scopes, assertion).ExecuteAsync();
            
   request.Headers.Authorization =
                                    new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
});
var graphClient = new GraphServiceClient(authProvider);
var users = graphClient.Me.MailFolders.Request().GetAsync().GetAwaiter().GetResult();

In the end I had to abandon using the ConfidentialClientApplicationBuilder, I still use PublicClientApplicationBuilder on the front end to get the users consent but then I handle everything else with the oauth2/v2.0/token rest services which returns and accepts refresh tokens.

That way I can ask the user for mailbox consent using PublicClientApplicationBuilder Access the user mailbox at any time using oauth2/v2.0/token

Related