How to cache token with Microsoft Graph for Java

1.2k Views Asked by At

I am using Microsoft Graph SDK for some requests however everytime I perform a GET request it does another request to get a token. I've tried reading documentation about this but I cannot find anything in Java.

Here is my implementation of my client

         ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
            .clientId(clientId)
            .clientSecret(clientSecret)
            .tenantId(tenantId)
            .httpClient(httpClient)
            .build();

I have also tried using the method .tokenCachePersistenceOptions() in my builder but I get this warning/error

c.m.a.m.CrossProcessCacheFileLock        : null

Thank you!

3

There are 3 best solutions below

4
On

To achieve the above requirement Firstly you need to Authenticate for implementing MSAL to get the token from Azure AD.

To obtain an access token, your app must be registered with the Microsoft identity platform and approved to access the Microsoft Graph resources it requires by either a user who is added as an owner for that application or an administrator.

For complete setup please refer this MS DOCUMENT Authentication and authorization basics for Microsoft Graph , This sample & GitHub sample|msgraph-sdk-java-core

0
On

I was looking for the same think and here's what I've implemented for it:

Implement your own authentication provider class:

public class DelegateAuthenticationProvider implements IAuthenticationProvider {
    private String token;

    public DelegateAuthenticationProvider(String token) {
        this.token = token;
    }

    @NotNull
    @Override
    public CompletableFuture<String> getAuthorizationTokenAsync(@NotNull URL url) {
        return CompletableFuture.completedFuture(token);
    }
}

Then you can use it as follow:

String token = "<YOUR_TOKEN_STRING>"
IAuthenticationProvider tokenCredentialAuthProvider = new DelegateAuthenticationProvider(token);

// Create the Graph Client with the given Token Provider
GraphServiceClient graphClient = GraphServiceClient.builder()
        .authenticationProvider(tokenCredentialAuthProvider)
        .buildClient();

If you get an GraphServiceException code 401 you should renew your token.

When you are successfully logged in with your clientSecretCredential, here's how you can get the token:

List<String> scopes = Arrays.asList("https://graph.microsoft.com/.default");
IAuthenticationProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(scopes, clientSecretCredential);
String token = tokenCredentialAuthProvider.getAuthorizationTokenAsync("https://graph.microsoft.com/v1.0/me").get()

Hope this helps.

0
On

You can override the authenticationProvider which is provided for the GraphServiceClient

import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenCredential;
import com.azure.core.credential.TokenRequestContext;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import org.jetbrains.annotations.NotNull;

import java.net.URL;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

public class CachingTokenCredentialAuthProvider extends TokenCredentialAuthProvider {
    private final TokenCredential tokenCredential;
    private final TokenRequestContext context;
    private AccessToken accessToken;

    public CachingTokenCredentialAuthProvider(@NotNull List<String> scopes, @NotNull TokenCredential tokenCredential) {
        super(scopes, tokenCredential);
        if (!scopes.isEmpty()) {
            this.context = new TokenRequestContext();
            this.context.setScopes(scopes);
            this.tokenCredential = Objects.requireNonNull(tokenCredential, "tokenCredential parameter cannot be null.");
        } else {
            throw new IllegalArgumentException("scopes parameter cannot be null or empty");
        }
    }

    @NotNull
    @Override
    public CompletableFuture<String> getAuthorizationTokenAsync(@NotNull URL requestUrl) {
        if (this.shouldAuthenticateRequestWithUrl(Objects.requireNonNull(requestUrl, "requestUrl parameter cannot be null"))) {
            if(this.accessToken != null && !OffsetDateTime.now().minusMinutes(1).isAfter(this.accessToken.getExpiresAt())) {
                return CompletableFuture.completedFuture(this.accessToken.getToken());
            }

            return this.tokenCredential.getToken(this.context).toFuture().thenApply(accessToken -> {
                saveToken(accessToken);
                return accessToken.getToken();
            });
        } else {
            return CompletableFuture.completedFuture(null);
        }
    }

    void saveToken(AccessToken accessToken) {
        this.accessToken = accessToken;
    }
}

This will cache the token until it one minute before it is no longer valid.