I have been working on an Azure Function. The function is daemon that doesn't require user interaction. Therefore, it uses application permissions to consume Microsoft Graph.
The idea is to have only one instance of Graph Service Client that will be consumed by all the instances of that Azure Functions. To do so, I have created a singleton class.
Considering that Microsoft.Graph.Auth is in preview, and will never go out preview, I have opted to use Microsoft.Identity package instead. I pass a delegate to the graph service client, that acquires token for the client. If the token is expired, the new token gets acquired automatically. AcquireTokenForClient(scopes) returns the same token again, however, if it is about to expire, it gets the new token.
- The question is that is it the right approach to handle the token refresh, considering there can be multiple instances of Azure Function running?
- Secondly, is it the right way to create authentication provider for graph service client using Microsoft.Identity? Or is there a better way?
- Lastly, is it a good idea to use Microsoft Graph SDK at all? Because, the documentation is using Microsoft.Graph.Auth which according to Microsoft will never go out of preview. There isn't much documentation of how and what to do instead.
My Code:
public class MSGraphAuth
{
private static MSGraphAuth _graphAuth;
private static GraphServiceClient _graphClient;
private static readonly object _lock = new object();
private MSGraphAuth() { }
public static MSGraphAuth GraphAuth
{
get
{
if (_graphAuth == null)
{
lock (_lock)
{
if (_graphAuth == null)
{
_graphAuth = new MSGraphAuth();
_graphAuth.InitializeGraphClient();
}
}
}
return _graphAuth;
}
}
public GraphServiceClient GraphClient
{
get
{
return _graphClient;
}
}
void InitializeGraphClient()
{
string authority = "{authority}";
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(AppSettings.MSGRAPHCLIENTID)
.WithAuthority(authority)
.WithClientSecret(AppSettings.MSGRAPHCLIENTSECRET)
.Build();
_graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
var scopes = new string[] { "https://graph.microsoft.com/.default" };
var authResult = await confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync();
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
}));
}
}
}