Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure: Unable to use RefreshToken to acquire a new AccessToken

I'm building an application that needs access to our clients' Office 365 Management Activities. I've followed the steps outlined in this Azure Active Directory overview, and am able to use the OAuth code to acquire an initial Access Token, as well as use this token to set up O365 subscriptions.

However, when I use the refresh_token provided with my initial token to acquire a new Access Token, I get the following error:

{"error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID '8f72f805-dfd2-428d-8b0e-771a98d26c16'. Send an interactive authorization request for this user and resource.\r\nTrace ID: df229c3f-8f28-420b-9ac3-321ab1b2ad09\r\nCorrelation ID: 0e0f2bcb-4b19-458a-8556-2a6d4e51379f\r\nTimestamp: 2016-10-03 17:33:20Z","error":"invalid_grant"}

Since I'm able to acquire and use the initial Access Token, I'm pretty sure that the user is granting my applications some permissions. Is there a specific permission that I need in order to acquire a new Access Token using the Refresh Token?

Edit: Specifically, I'm using the com.microsoft.azure::adal4j java package, AuthenticationContext class, acquireTokenByAuthorizationCode and acquireTokenByRefreshToken methods:

public class AzureProvisioner {
    private final AuthenticationContext authService = new AuthenticationContext(
            "https://login.windows.net/common/oauth2/token", true, Executors.newSingleThreadExecutor());
    private final ClientCredential clientCredential = new ClientCredential("azureAppId", "azureAppSecret");
    public static final String resource = "https://manage.office.com";
    // Internal implementation of REST interface; Microsoft didn't provide a Java Library
    final Office365ManagementApi managementApi;

    public void acquireToken(final String authCode, final URI redirectUri) {
        final AuthenticationResult authResult = authService.acquireTokenByAuthorizationCode(
                authCode, redirectUri, clientCredential, resource, null).get()
        // internal library code, gets the "tid" field from parsing the JWT token
        final String tenantId = JwtAccessToken.fromToken(authResult.getAccessToken()).getTid();

        // works
        createInitialSubscription(customerId, authResult.getAccessToken(), tenantId);

        // throws an error
        final AuthenticationResult refreshResult = authService.acquireTokenByRefreshToken(
                authResult.getRefreshToken(), clientCredential, null).get();
    }

    private void createInitialSubscription(final String accessToken, final String tenantId) {
        final String authHeader = "Authorization: Bearer " + accessToken;
        final String contentType = "Audit.AzureActiveDirectory";
        // internal implementation
        final CreateWebhookRequest requestBody = new CreateWebhookRequest();
        managementApi.createSubscription(authHeader, tenantId, contentType, requestBody);
    }
}

The same code, without any external dependencies, also does not work for me:

public class AzureProvisioner {
    private final AuthenticationContext authService = new AuthenticationContext(
            "https://login.windows.net/common/oauth2/token", true, Executors.newSingleThreadExecutor());
    private final ClientCredential clientCredential = new ClientCredential("8f72f805-dfd2-428d-8b0e-771a98d26c16", "secret");
    public final String resource = "https://manage.office.com";
    private URI redirectUri = new URI("https://localhost");

    private static final String oAuthUrl = "https://login.windows.net/common/oauth2/authorize?response_type=code&client_id=8f72f805-dfd2-428d-8b0e-771a98d26c16&resource=https%3A%2F%2Fmanage.office.com&redirect_uri=https%3A%2F%2Flocalhost";

    public AzureProvisioner() throws Exception {
        // do nothing
    }

    public static void main(String... args) throws Exception {
        final String authCode = "AQABAAAAAADRNYRQ3dhRSrm...";
        new AzureProvisioner().acquireToken(authCode);
    }

    public void acquireToken(final String authCode) throws Exception {
        final AuthenticationResult authResult = authService.acquireTokenByAuthorizationCode(
                authCode, redirectUri, clientCredential, resource, null).get();
        System.out.println(authResult.getAccessToken());

        // throws an error
        final AuthenticationResult refreshResult = authService.acquireTokenByRefreshToken(
                authResult.getRefreshToken(), clientCredential, resource, null).get();
        System.out.println(refreshResult.getAccessToken());
    }
}

Using a proxy, I took a trace of the https refresh request:

Method: POST
Protocol-Version: HTTP/1.1
Protocol: https
Host: login.windows.net
File: /common/oauth2/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 876

refresh_token={token}
&resource=https%3A%2F%2Fmanage.office.com
&grant_type=refresh_token
&scope=openid
&client_secret={secret}
&client_id=8f72f805-dfd2-428d-8b0e-771a98d26c16
like image 372
Andrew Rueckert Avatar asked Sep 24 '16 00:09

Andrew Rueckert


People also ask

How do I get a new refresh token OAuth2?

Because OAuth2 access expires after a limited time, an OAuth2 refresh token is used to automatically renew OAuth2 access. Click the tab for the programming language you're using, and follow the instructions to generate an OAuth2 refresh token and set up the configuration file for your client.

When should I use refresh token to get access token?

You can use a refresh token only to generate an access token; you can't use it to make an authenticated API call. This is useful in cases where the client making API calls doesn't have access to the private key. A third-party system can generate the refresh token and provide it to the client making API calls.

How do I refresh my Accesstoken?

These client credentials and the refresh_token can be used to create a new value for the access_token . To refresh the access token, select the Refresh access token API call within the Authorization folder of the Postman collection. Next, click the Send button to request a new access_token .


1 Answers

It turns out that the root issue was with my application permissions. Under My Application > Settings > Required Permissions > Office 365 Management APIs, I had selected the "Application Permissions", where I needed to select the "Delegated Permissions". Swapping those over, my code immediately started working as expected.

wrong!

like image 153
Andrew Rueckert Avatar answered Oct 06 '22 06:10

Andrew Rueckert