Skip to content

Acquiring Tokens

Avery-Dunn edited this page Jun 15, 2023 · 12 revisions

As explained in scenarios, there are many ways of acquiring a token. Some require user interactions through a web browser. Some don't require any user interactions. In general the way to acquire a token is different depending on the application type- public client application (Desktop / Mobile) or a confidential client application (Web App, Web API, daemon application like a windows service)

Pre-requisites

Before acquiring tokens with MSAL4J:

Token acquisition methods

Follow the topics below for detailed explanation with MSAL4J code usage for each token acquisition method.

Public client applications:

  • Acquire tokens interactively with system browser
  • Acquire tokens by authorization code after letting the user sign-in through the authorization request URL.
  • It's also possible (but not recommended) to get a token with a username and password.
  • For applications running on Windows machines and joined to a domain or to Azure AD, it is possible to acquire a token silently, leveraging Integrated Windows Authentication (IWA).
  • Finally, for applications running on devices which don't have a web browser, it's possible to acquire a token through the device code flow, which provides the user with a URL and a code. The user goes to a web browser on another device, enters the code and signs-in, and then Azure AD returns back a token to the browser-less device.

Confidential client applications:

  • Acquire token as the application itself using client credentials, and not for a user. For example, in apps which process users in batches and not a particular user such as in syncing tools.
  • In the case of Web Apps or Web APIs calling another downstream Web API in the name of the user, use the On Behalf Of flow to acquire a token based on some User assertion (SAML for instance, or a JWT token).
  • For Web apps in the name of a user, acquire tokens by authorization code after letting the user sign-in through the authorization request URL. This is typically the mechanism used by an application which lets the user sign-in using Open ID Connect, but then wants to access Web APIs for this particular user.

MSAL4J caches tokens

For both Public client and Confidential client applications, MSAL maintains an in-memory token cache, and applications should try to get a token from the cache first before any other means (except in the case of client credentials, which looks at the cache by default).

In order to retrieve cached tokens, rather than using one of the flows described above you will use the acquireTokenSilently API. This API is available for both public and confidential clients, and the basic behavior of the API is:

  • If there is a valid cached token for the account/scopes you send as parameters, it will be returned as an AuthenticationResult like any other flow
  • If there is a valid-but-expired cached token, MSAL Java will attempt to refresh the token and return it as an AuthenticationResult
  • If there is no cached token for the account/scopes you set as parameters, then it will return an exception saying that there was no cached token

Here is some sample code showing the recommended pattern for acquiring cached tokens and new ones:

//...
//In some other part of your code, make the client application (public or confidential).
//This object will have an in-memory cache associated with it, 
//  and the cache will exist for as long as the public/confidential client app object does
PublicClientApplication pca = new PublicCLientApplication.builder(...);
//...


//In some method for acquiring a token....
public IAuthenticationResult getAToken(PublicClientApplication pca) {
    //Get the account you want to retrieve a token for
    //Doing this outside of this method is probably more efficient, as you can re-use the list of accounts for multiple calls
    Set<IAccount> accountsInCache = pca.getAccounts().join();
    //Filter the accounts in some way (this example just uses the first one in the list for simplicity)
    IAccount account = accountsInCache.iterator().next();

    IAuthenticationResult result;
    try {
        //Build the SilentParameters object using the account you want to get the token for,
        //  and the scopes you want the token to have
        SilentParameters silentParameters =
            SilentParameters
                    .builder(someScopes, account)
                    .build();

        //Try to acquire the token silently. This will either return a cached token for the account/scopes
        //  defined in the silentParameters object, or it will cause an exception saying their was no cached token
        result = pca.acquireTokenSilently(silentParameters).join();
    } catch (Exception ex) {
        //If an MsalException is thrown, something went wrong with the silent call and you should try another flow
        if (ex.getCause() instanceof MsalException) {
            //(interactive flow used here just as an example, swap this out with your preferred flow)
            //Build the InteractiveRequestParameters using the scopes you want the token to have
            InteractiveRequestParameters parameters = InteractiveRequestParameters
                .builder(new URI("http://localhost"))
                .scopes(someScopes)
                .build();

            //Try to acquire a brand new token
            result = pca.acquireToken(parameters).join();
        } else {
            // Handle other exceptions accordingly
        throw ex;
        }
    }
    return result;
}
Clone this wiki locally