Search code examples
c#asp.net-core.net-coremicrosoft-graph-apimicrosoft-graph-sdks

Best way to use Microsoft.Graph SDK when I already have users' refresh tokens stored in database?


I'm building a multi-user, multi-tenant app that will access the Microsoft Graph API on behalf of many users while they're offline.

Because the app uses the Microsoft Identity for external OIDC authentication, during the user's first login, I already requested the appropriate scopes/consents and received the access/refresh tokens issued by Microsoft. The tokens are saved in the database.

Now I want to use Microsoft.Graph which makes accessing the Graph API much easier, but it seems that a big part of this SDK was written to retrieve tokens, which I do not need because I already have the tokens.

I do, however, want the SDK client to automatically use the stored refresh token to obtain new access tokens, instead of having to manually handle the refreshing logic myself, if possible.

Upon research, I found that I can pass in an null for the AuthenticationProvider when constructing the GraphServiceClient, and manually attach bearer token to the client like this:

var graphClient = new GraphServiceClient(authenticationProvider: null);

var requestHeaders = new List<HeaderOption>() 
                  { new HeaderOption("Authorization", "Bearer " + myToken) };

var me = await graphClient.Me.Request(requestHeaders).GetAsync();

This does work and bypasses the client's token retrieval logic, but the problem now is that it won't handle access token expiration/renewal. So I have to use separate code to make sure I always pass in a non-expired access token, and renew the token myself using the refresh token if necessary.

I wonder if there is a way to customize GraphServiceClient such that it doesn't try to obtain tokens using separate OAuth2/OIDC flows, but instead knows how to find an existing refresh token stored in my database, and use that refresh token to manage its renewal/expiration logic like it does for tokents it receives with its regular flows.

The ideal flow works like this:

  1. Pass in a parameter (the user's ID in my database) to create a GraphServiceClient.

  2. The client uses this UserID to lookup the stored tokens in my database (EF Core).

  3. If the stored access token already expired, use the stored refresh token to get a new one, and update the tokens in the database.

Would this be possible with the SDK?

Your advice will be greatly appreciated.


Solution

  • You can implement the IAuthenticationProvider interface in your own custom class, then do the necessary token checking/refresh in the AuthenticateRequestAsync function. See https://github.com/microsoftgraph/msgraph-training-dotnet-core/blob/main/demo/GraphTutorial/Authentication/DeviceCodeAuthProvider.cs for an example.

    I'd recommend looking at the MSAL library to handle all of the token logic for you. You can hook into it's token cache to serialize it how you want (to store it in your database, for example). In the example I linked I'm using MSAL, and you can see I don't have to do any checking for expired tokens, it's all handled for me.