Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/main/java/com/auth0/client/auth/AuthAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public class AuthAPI {
private static final String KEY_CLIENT_ASSERTION_TYPE = "client_assertion_type";
private static final String KEY_SUBJECT_TOKEN = "subject_token";
private static final String KEY_SUBJECT_TOKEN_TYPE = "subject_token_type";
private static final String KEY_REQUESTED_TOKEN_TYPE = "requested_token_type";
private static final String KEY_LOGIN_HINT = "login_hint";
private static final String PATH_OAUTH = "oauth";
private static final String PATH_TOKEN = "token";
private static final String PATH_DBCONNECTIONS = "dbconnections";
Expand Down Expand Up @@ -840,6 +842,54 @@ public TokenRequest exchangeToken(String subjectToken, String subjectTokenType)
return request;
}

/**
* Creates a request to exchange an Auth0 refresh token for a federated identity provider's access token
* using the Token Vault grant
* {@code urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token}.
* The connection must have the token vault enabled, and client authentication
* (client secret or client assertion) is required as this must be a private client.
* <pre>
* {@code
* try {
* TokenHolder result = authAPI.getTokenForConnection("google-oauth2", refreshToken, "google-user-id")
* .execute()
* .getBody();
* String federatedAccessToken = result.getAccessToken();
* } catch (Auth0Exception e) {
* //Something happened
* }
* }
* </pre>
*
* @see <a href="https://auth0.com/docs/secure/tokens/token-vault">Token Vault documentation</a>
* @param connection the name of the federated connection to obtain an access token for
* (for example {@code google-oauth2}). Must not be null.
* @param refreshToken a valid Auth0 refresh token to exchange. Must not be null.
* @param loginHint the user's ID within the identity provider specified by the connection
* (for example, the Google user ID when the connection is {@code google-oauth2}).
* May be null, in which case no {@code login_hint} is sent.
* @return a Request to configure and execute.
*/
public TokenRequest getTokenForConnection(String connection, String refreshToken, String loginHint) {
Asserts.assertNotNull(connection, "connection");
Asserts.assertNotNull(refreshToken, "refresh token");

TokenRequest request = new TokenRequest(client, getTokenUrl());
request.addParameter(KEY_CLIENT_ID, clientId);
request.addParameter(
KEY_GRANT_TYPE, "urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token");
request.addParameter(KEY_SUBJECT_TOKEN, refreshToken);
request.addParameter(KEY_SUBJECT_TOKEN_TYPE, "urn:ietf:params:oauth:token-type:refresh_token");
request.addParameter(
KEY_REQUESTED_TOKEN_TYPE, "http://auth0.com/oauth/token-type/federated-connection-access-token");
request.addParameter(KEY_CONNECTION, connection);
if (loginHint != null) {
request.addParameter(KEY_LOGIN_HINT, loginHint);
}
addClientAuthentication(request, true);
return request;
}

/**
* Creates a request to revoke an existing Refresh Token.
* Confidential clients (Regular Web Apps) <strong>must</strong> have a client secret configured on this {@code AuthAPI} instance.
Expand Down
76 changes: 76 additions & 0 deletions src/test/java/com/auth0/client/auth/AuthAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,82 @@ public void shouldCreateTokenExchangeRequestWithClientAssertion() throws Excepti
assertThat(response.getAccessToken(), not(emptyOrNullString()));
}

// Token Vault - Federated Connection Access Token

@Test
public void shouldThrowOnGetTokenForConnectionWithNullConnection() {
verifyThrows(
IllegalArgumentException.class,
() -> api.getTokenForConnection(null, "test-refresh-token", null),
"'connection' cannot be null!");
}

@Test
public void shouldThrowOnGetTokenForConnectionWithNullRefreshToken() {
verifyThrows(
IllegalArgumentException.class,
() -> api.getTokenForConnection("google-oauth2", null, null),
"'refresh token' cannot be null!");
}

@Test
public void shouldCreateGetTokenForConnectionRequest() throws Exception {
TokenRequest request = api.getTokenForConnection("google-oauth2", "test-refresh-token", null);
assertThat(request, is(notNullValue()));

server.jsonResponse(AUTH_TOKENS, 200);
TokenHolder response = request.execute().getBody();
RecordedRequest recordedRequest = server.takeRequest();

assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/oauth/token"));
assertThat(recordedRequest, hasHeader("Content-Type", "application/json"));

Map<String, Object> body = bodyFromRequest(recordedRequest);
assertThat(
body,
hasEntry(
"grant_type",
"urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token"));
assertThat(body, hasEntry("client_id", CLIENT_ID));
assertThat(body, hasEntry("client_secret", CLIENT_SECRET));
assertThat(body, hasEntry("subject_token", "test-refresh-token"));
assertThat(body, hasEntry("subject_token_type", "urn:ietf:params:oauth:token-type:refresh_token"));
assertThat(
body,
hasEntry(
"requested_token_type", "http://auth0.com/oauth/token-type/federated-connection-access-token"));
assertThat(body, hasEntry("connection", "google-oauth2"));
assertThat(body, not(hasKey("login_hint")));

assertThat(response, is(notNullValue()));
assertThat(response.getAccessToken(), not(emptyOrNullString()));
}

@Test
public void shouldCreateGetTokenForConnectionRequestWithLoginHint() throws Exception {
TokenRequest request = api.getTokenForConnection("google-oauth2", "test-refresh-token", "google-user-id");
assertThat(request, is(notNullValue()));

server.jsonResponse(AUTH_TOKENS, 200);
TokenHolder response = request.execute().getBody();
RecordedRequest recordedRequest = server.takeRequest();

Map<String, Object> body = bodyFromRequest(recordedRequest);
assertThat(body, hasEntry("connection", "google-oauth2"));
assertThat(body, hasEntry("login_hint", "google-user-id"));

assertThat(response, is(notNullValue()));
assertThat(response.getAccessToken(), not(emptyOrNullString()));
}

@Test
public void getTokenForConnectionRequiresClientAuthentication() {
verifyThrows(
IllegalStateException.class,
() -> apiNoClientAuthentication.getTokenForConnection("google-oauth2", "test-refresh-token", null),
"A client secret or client assertion signing key is required for this operation");
}

// Login with Passwordless

@Test
Expand Down
Loading