Reputation: 5215
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
Upvotes: 17
Views: 2314
Reputation: 5215
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.
Upvotes: 2
Reputation: 551
ADAL uses the stored refresh tokens automatically and transparently, you aren't required to perform any explicit action. AcquireTOkenByRefreshToken is in the ADAL surface for legacy reasons, and has been removed from version 3.x. More background at http://www.cloudidentity.com/blog/2015/08/13/adal-3-didnt-return-refresh-tokens-for-5-months-and-nobody-noticed/
Upvotes: 0