Search code examples
javaazureoauth-2.0refresh-tokenadal4j

ADAL4j java - use refresh token with username and password to get the access token


I am connecting to Azure AD enabled API using java back-end server. I am able to get the Access Token by following java code.

    String tenantId = "************";
    String username = "***************";
    String password = "*************";
    String clientId = "**********";
    String resource = "***********";
    String userEmail = "**********";


    AuthenticationContext authContext = null;
    AuthenticationResult authResult = null;
    ExecutorService service = null;

    try
    {
        service = Executors.newFixedThreadPool( 1 );
        String url = "https://login.microsoftonline.com/" + tenantId + "/oauth2/authorize";
        authContext = new AuthenticationContext( url, false, service );
        Future<AuthenticationResult> future = authContext.acquireToken(
                resource,
                clientId,
                userEmail,
                password,
                null );

        authResult = future.get();

    }
    catch( Exception ex )
    {
        ex.printStackTrace();
    }

Please note that API provider is is not supporting client credentials currently.

The issue for me is, using the refresh token received in above code to get a new access token.

ADAL4j java library doesn't seems to have any methods supporting this. A Documentation for java library

But in .NET library there are methods like,

public AuthenticationResult AcquireTokenByRefreshToken(
string refreshToken,
string clientId,
string resource
)

For refreshing access token without any credential provided.

Why these methods are not provided in Java library?. Are there any restrictions? And what are possible workarounds?

Thanks in advance.


Solution

  • As far as I know, although the Java ADAL4J library doesn't support the method

    public AuthenticationResult AcquireTokenByRefreshToken(
    string refreshToken,
    string clientId,
    string resource
    )
    

    which is supported in .Net library, both of the two types of libraries are implemented via HTTP REST API.

    You could refer to the Refreshing the access tokens in the official document

    // Line breaks for legibility only
    
    POST /{tenant}/oauth2/token HTTP/1.1
    Host: https://login.microsoftonline.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=6731de76-14a6-49ae-97bc-6eba6914391e
    &refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
    &grant_type=refresh_token
    &resource=https%3A%2F%2Fservice.contoso.com%2F
    &client_secret=JqQX2PNo9bpM0uEihUPzyrh    // NOTE: Only required for web apps
    

    I use Postman to test a request for acquiring accessToken by refreshToken without credentials for your reference:

    enter image description here

    Corresponded, I implemented the request with the following Java code

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    import com.microsoft.aad.adal4j.AuthenticationContext;
    import com.microsoft.aad.adal4j.AuthenticationResult;
    
    public class AcquireTokenByRefreshToken {
    
        static String tenantId = "***";
        static String username = "***";
        static String password = "***";
        static String clientId = "***";
        static String resource = "https://graph.windows.net";
        static String userEmail = "***";
    
        public static void main(String[] args) throws MalformedURLException, IOException {
            AuthenticationContext authContext = null;
            AuthenticationResult authResult = null;
            ExecutorService service = null;
    
            try {
                service = Executors.newFixedThreadPool(1);
                String url = "https://login.microsoftonline.com/" + tenantId + "/oauth2/authorize";
                authContext = new AuthenticationContext(url, false, service);
                Future<AuthenticationResult> future = authContext.acquireToken(resource, clientId, userEmail, password,
                        null);
    
                authResult = future.get();
                System.out.println("get access token: \n" + authResult.getAccessToken());
                System.out.println("get refresh token: \n" + authResult.getRefreshToken());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            // get access token by refresh token
            getToken(authResult.getRefreshToken());
        }
    
        public static void getToken(String refreshToken) throws IOException {
    
            String encoding = "UTF-8";
            String params = "client_id=" + clientId + "&refresh_token=" + refreshToken
                    + "&grant_type=refresh_token&resource=https%3A%2F%2Fgraph.windows.net";
            String path = "https://login.microsoftonline.com/" + tenantId + "/oauth2/token";
            byte[] data = params.getBytes(encoding);
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));
            conn.setConnectTimeout(5 * 1000);
            OutputStream outStream = conn.getOutputStream();
            outStream.write(data);
            outStream.flush();
            outStream.close();
            System.out.println(conn.getResponseCode());
            System.out.println(conn.getResponseMessage());
    
            BufferedReader br = null;
            if (conn.getResponseCode() != 200) {
                br = new BufferedReader(new InputStreamReader((conn.getErrorStream())));
            } else {
                br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
            }
            System.out.println("Response body : " + br.readLine());
        }
    
    }
    

    The result printed in console as below :

    enter image description here

    Hope it helps you.