Skip to content

Commit

Permalink
Merge pull request #86 from auth0/revoke-refresh-token
Browse files Browse the repository at this point in the history
Add method to revoke a refresh_token
  • Loading branch information
lbalmaceda authored Apr 27, 2017
2 parents a397402 + 84455f7 commit 6744d01
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ public class AuthenticationAPIClient {
private static final String PASSWORD_KEY = "password";
private static final String EMAIL_KEY = "email";
private static final String PHONE_NUMBER_KEY = "phone_number";
private static final String OAUTH_CODE_KEY = "code";
private static final String REDIRECT_URI_KEY = "redirect_uri";
private static final String TOKEN_KEY = "token";
private static final String DELEGATION_PATH = "delegation";
private static final String ACCESS_TOKEN_PATH = "access_token";
private static final String SIGN_UP_PATH = "signup";
Expand All @@ -90,8 +93,7 @@ public class AuthenticationAPIClient {
private static final String RESOURCE_OWNER_PATH = "ro";
private static final String TOKEN_INFO_PATH = "tokeninfo";
private static final String USER_INFO_PATH = "userinfo";
private static final String OAUTH_CODE_KEY = "code";
private static final String REDIRECT_URI_KEY = "redirect_uri";
private static final String REVOKE_PATH = "revoke";
private static final String HEADER_AUTHORIZATION = "Authorization";

private final Auth0 auth0;
Expand Down Expand Up @@ -617,6 +619,43 @@ public DatabaseConnectionRequest<Void, AuthenticationException> resetPassword(@N
return new DatabaseConnectionRequest<>(request);
}

/**
* Request the revoke of a given refresh_token. Once revoked, the refresh_token cannot be used to obtain new tokens.
* The client must be of type 'Native' or have the 'Token Endpoint Authentication Method' set to 'none' for this endpoint to work.
*
* Example usage:
* <pre>
* {@code
* client.revokeToken("{refresh_token}")
* .start(new BaseCallback<Void>() {
* {@literal}Override
* public void onSuccess(Void payload) {}
*
* {@literal}Override
* public void onFailure(AuthenticationException error) {}
* });
* }
* </pre>
*
* @param refreshToken the token to revoke
* @return a request to start
*/
@SuppressWarnings("WeakerAccess")
public Request<Void, AuthenticationException> revokeToken(@NonNull String refreshToken) {
final Map<String, Object> parameters = ParameterBuilder.newBuilder()
.setClientId(getClientId())
.set(TOKEN_KEY, refreshToken)
.asDictionary();

HttpUrl url = HttpUrl.parse(auth0.getDomainUrl()).newBuilder()
.addPathSegment(OAUTH_PATH)
.addPathSegment(REVOKE_PATH)
.build();

return factory.POST(url, client, gson, authErrorBuilder)
.addParameters(parameters);
}

/**
* Requests new Credentials using a valid Refresh Token. The received token will have the same audience and scope as first requested. How the new Credentials are requested depends on the {@link Auth0#isOIDCConformant()} flag.
* - If the instance is OIDC Conformant the endpoint will be /oauth/token with 'refresh_token' grant, and the response will include an id_token and an access_token if 'openid' scope was requested when the refresh_token was obtained.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,46 @@ public void shouldFetchProfileAfterLoginRequest() throws Exception {
assertThat(callback, hasPayloadOfType(Authentication.class));
}


@Test
public void shouldRevokeToken() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);

mockAPI.willReturnSuccessfulEmptyBody();
final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
client.revokeToken("refreshToken")
.start(callback);

final RecordedRequest request = mockAPI.takeRequest();
assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
assertThat(request.getPath(), equalTo("/oauth/revoke"));

Map<String, String> body = bodyFromRequest(request);
assertThat(body, hasEntry("client_id", CLIENT_ID));
assertThat(body, hasEntry("token", "refreshToken"));

assertThat(callback, hasNoError());
}

@Test
public void shouldRevokeTokenSync() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);

mockAPI.willReturnSuccessfulEmptyBody();
client.revokeToken("refreshToken")
.execute();

final RecordedRequest request = mockAPI.takeRequest();
assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
assertThat(request.getPath(), equalTo("/oauth/revoke"));

Map<String, String> body = bodyFromRequest(request);
assertThat(body, hasEntry("client_id", CLIENT_ID));
assertThat(body, hasEntry("token", "refreshToken"));
}

@Test
public void shouldRenewAuthWithOAuthTokenIfOIDCConformant() throws Exception {
Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ public AuthenticationAPI willReturnSuccessfulSignUp() {
return this;
}

public AuthenticationAPI willReturnSuccessfulEmptyBody() {
server.enqueue(responseEmpty(200));
return this;
}

public AuthenticationAPI willReturnSuccessfulLogin() {
String json = "{\n" +
" \"refresh_token\": \"" + REFRESH_TOKEN + "\",\n" +
Expand Down Expand Up @@ -175,7 +180,12 @@ public AuthenticationAPI willReturnApplicationResponseWithBody(String body, int
return this;
}

private MockResponse responseWithPlainText(String statusMessage, int statusCode){
private MockResponse responseEmpty(int statusCode) {
return new MockResponse()
.setResponseCode(statusCode);
}

private MockResponse responseWithPlainText(String statusMessage, int statusCode) {
return new MockResponse()
.setResponseCode(statusCode)
.addHeader("Content-Type", "text/plain")
Expand Down

0 comments on commit 6744d01

Please sign in to comment.