Azure:无法使用 RefreshToken 获取新的 AccessToken
Azure: Unable to use RefreshToken to acquire a new AccessToken
我正在构建一个需要访问我们客户的 Office 365 Management Activities. I've followed the steps outlined in this Azure Active Directory 概览的应用程序,并且能够使用 OAuth 代码获取初始访问令牌,以及使用此令牌设置 O365订阅。
但是,当我使用随初始令牌提供的 refresh_token
获取新的访问令牌时,出现以下错误:
{"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"}
由于我能够获取并使用初始访问令牌,我很确定用户正在授予我的应用程序 一些 权限。是否需要特定权限才能使用刷新令牌获取新的访问令牌?
编辑:
具体来说,我正在使用 com.microsoft.azure::adal4j
java package, AuthenticationContext class, acquireTokenByAuthorizationCode and acquireTokenByRefreshToken 方法:
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
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/
处有更多背景资料
事实证明,根本问题出在我的应用程序权限上。在 My Application > Settings > Required Permissions > Office 365 Management APIs
下,我 select 编辑了 "Application Permissions",我需要 select "Delegated Permissions"。交换这些,我的代码立即开始按预期工作。
我正在构建一个需要访问我们客户的 Office 365 Management Activities. I've followed the steps outlined in this Azure Active Directory 概览的应用程序,并且能够使用 OAuth 代码获取初始访问令牌,以及使用此令牌设置 O365订阅。
但是,当我使用随初始令牌提供的 refresh_token
获取新的访问令牌时,出现以下错误:
{"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"}
由于我能够获取并使用初始访问令牌,我很确定用户正在授予我的应用程序 一些 权限。是否需要特定权限才能使用刷新令牌获取新的访问令牌?
编辑:
具体来说,我正在使用 com.microsoft.azure::adal4j
java package, AuthenticationContext class, acquireTokenByAuthorizationCode and acquireTokenByRefreshToken 方法:
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
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/
处有更多背景资料事实证明,根本问题出在我的应用程序权限上。在 My Application > Settings > Required Permissions > Office 365 Management APIs
下,我 select 编辑了 "Application Permissions",我需要 select "Delegated Permissions"。交换这些,我的代码立即开始按预期工作。