Azure: невозможно использовать RefreshToken для приобретения нового AccessToken

Я создаю приложение, которое нуждается в доступе к нашим менеджерам. Я выполнил действия, описанные в этом обзоре Azure Active Directory, и я могу использовать код OAuth для получения первоначального токена доступа, а также использовать этот токен для настроить подписки O365.

Однако, когда я использую refresh_token, снабженный моим первым токеном, чтобы получить новый токен доступа, я получаю следующую ошибку:

{ "error_description": "AADSTS65001: Пользователь или администратор не согласился использовать приложение с идентификатором '8f72f805-dfd2-428d-8b0e-771a98d26c16'. Отправьте запрос интерактивной авторизации для этого пользователя и ресурса. \r\nTrace ID: df229c3f-8f28-420b-9ac3-321ab1b2ad09\r\nКорреляция ID: 0e0f2bcb-4b19-458a-8556-2a6d4e51379f\r\nПримечание: 2016-10-03 17: 33: 20Z", "error": "invalid_grant" }

Поскольку я могу приобрести и использовать начальный токен доступа, я уверен, что пользователь предоставляет моим приложениям некоторые разрешения. Требуется ли определенное разрешение для приобретения нового токена доступа с помощью токена обновления?

Edit: В частности, я использую пакет com.microsoft.azure::adal4j java, класс AuthenticationContext, приобретатьTokenByAuthorizationCode и purchaseTokenByRefreshToken:

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);
    }
}

Тот же код, без каких-либо внешних зависимостей, также не работает для меня:

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());
    }
}

Используя прокси, я взял трассировку запроса обновления https:

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

Ответы

Ответ 1

Оказывается, проблема с правами root была связана с моими разрешениями на приложения. В разделе My Application > Settings > Required Permissions > Office 365 Management APIs я выбрал "Разрешения для приложений", где мне нужно было выбрать "делегированные разрешения". Меняя код, мой код сразу же начал работать, как ожидалось.

wrong!

Ответ 2

ADAL использует сохраненные токены обновления автоматически и прозрачно, вы не обязаны выполнять какие-либо явные действия. AcquireTOkenByRefreshToken находится на поверхности ADAL по причинам, устаревшим, и был удален из версии 3.x. Больше фона на http://www.cloudidentity.com/blog/2015/08/13/adal-3-didnt-return-refresh-tokens-for-5-months-and-nobody-noticed/