Skip to content

Commit a86538c

Browse files
authored
feat(java-sdk): configurable token endpoint (#240)
2 parents 1962119 + d973ac2 commit a86538c

File tree

3 files changed

+68
-39
lines changed

3 files changed

+68
-39
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ docs/openapi/*.json-e
88
.dccache
99

1010
clients/**/*
11+
12+
# JetBrains IDEs
13+
.idea/
14+
*.iml

config/clients/java/template/creds-OAuth2Client.java.mustache

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,27 @@ import {{configPackage}}.*;
77
import {{errorsPackage}}.ApiException;
88
import {{errorsPackage}}.FgaInvalidParameterException;
99
import java.io.IOException;
10-
import java.net.HttpURLConnection;
11-
import java.net.http.HttpClient;
10+
import java.net.URI;
1211
import java.net.http.HttpRequest;
13-
import java.net.http.HttpResponse;
1412
import java.time.Instant;
1513
import java.util.concurrent.CompletableFuture;
1614

1715
public class OAuth2Client {
16+
public static final String DEFAULT_TOKEN_ENDPOINT_PATH = "/oauth/token";
1817
private final ApiClient apiClient;
19-
private final Credentials credentials;
2018
private final AccessToken token = new AccessToken();
2119
private final CredentialsFlowRequest authRequest;
22-
private final String apiTokenIssuer;
20+
private final String tokenEndpointUrl;
2321
2422
/**
2523
* Initializes a new instance of the {@link OAuth2Client} class
2624
*
2725
* @param configuration Configuration, including credentials, that can be used to retrieve an access tokens
2826
*/
29-
public OAuth2Client(Configuration configuration, ApiClient apiClient) throws FgaInvalidParameterException {
30-
this.credentials = configuration.getCredentials();
31-
27+
public OAuth2Client(Configuration configuration, ApiClient apiClient) {
28+
Credentials credentials = configuration.getCredentials();
3229
this.apiClient = apiClient;
33-
this.apiTokenIssuer = credentials.getClientCredentials().getApiTokenIssuer();
30+
this.tokenEndpointUrl = buildTokenEndpointUrl(credentials.getClientCredentials().getApiTokenIssuer());
3431
this.authRequest = new CredentialsFlowRequest();
3532
this.authRequest.setClientId(credentials.getClientCredentials().getClientId());
3633
this.authRequest.setClientSecret(credentials.getClientCredentials().getClientSecret());
@@ -65,10 +62,11 @@ public class OAuth2Client {
6562
try {
6663
byte[] body = apiClient.getObjectMapper().writeValueAsBytes(authRequest);
6764
68-
Configuration config = new Configuration().apiUrl("https://" + apiTokenIssuer);
65+
Configuration config = new Configuration().apiUrl(tokenEndpointUrl);
66+
67+
HttpRequest.Builder requestBuilder = ApiClient.requestBuilder("POST", "", body, config);
6968
70-
HttpRequest request = ApiClient.requestBuilder("POST", "/oauth/token", body, config)
71-
.build();
69+
HttpRequest request = requestBuilder.build();
7270
7371
return new HttpRequestAttempt<>(request, "exchangeToken", CredentialsFlowResponse.class, apiClient, config)
7472
.attemptHttpRequest()
@@ -77,4 +75,18 @@ public class OAuth2Client {
7775
throw new ApiException(e);
7876
}
7977
}
78+
79+
private static String buildTokenEndpointUrl(String issuer) {
80+
var uri = URI.create(issuer);
81+
82+
if (uri.getScheme() == null) {
83+
uri = URI.create("https://" + issuer);
84+
}
85+
86+
if (uri.getPath().isEmpty() || uri.getPath().equals("/")) {
87+
uri = URI.create(uri.getScheme() + "://" + uri.getAuthority() + DEFAULT_TOKEN_ENDPOINT_PATH);
88+
}
89+
90+
return uri.toString();
91+
}
8092
}

config/clients/java/template/creds-OAuth2ClientTest.java.mustache

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,56 @@ import com.fasterxml.jackson.databind.ObjectMapper;
99
import com.pgssoft.httpclient.HttpClientMock;
1010
import {{clientPackage}}.ApiClient;
1111
import {{configPackage}}.*;
12-
import {{errorsPackage}}.FgaInvalidParameterException;
13-
import org.junit.jupiter.api.BeforeEach;
14-
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.Arguments;
14+
import org.junit.jupiter.params.provider.MethodSource;
15+
16+
import java.util.stream.Stream;
17+
1518

1619
class OAuth2ClientTest {
1720
private static final String CLIENT_ID = "client";
1821
private static final String CLIENT_SECRET = "secret";
1922
private static final String AUDIENCE = "audience";
2023
private static final String GRANT_TYPE = "client_credentials";
21-
private static final String API_TOKEN_ISSUER = "test.fga.dev";
22-
private static final String POST_URL = "https://" + API_TOKEN_ISSUER + "/oauth/token";
2324
private static final String ACCESS_TOKEN = "0123456789";
2425
2526
private final ObjectMapper mapper = new ObjectMapper();
2627
private HttpClientMock mockHttpClient;
2728
28-
private OAuth2Client oAuth2;
29+
private static Stream<Arguments> issuersTokenEndpoint() {
30+
return Stream.of(
31+
Arguments.of("issuer.fga.example", "https://issuer.fga.example/oauth/token"),
32+
Arguments.of("https://issuer.fga.example", "https://issuer.fga.example/oauth/token"),
33+
Arguments.of("https://issuer.fga.example/", "https://issuer.fga.example/oauth/token"),
34+
Arguments.of("https://issuer.fga.example:8080", "https://issuer.fga.example:8080/oauth/token"),
35+
Arguments.of("https://issuer.fga.example:8080/", "https://issuer.fga.example:8080/oauth/token"),
36+
Arguments.of("issuer.fga.example/some_endpoint", "https://issuer.fga.example/some_endpoint"),
37+
Arguments.of("https://issuer.fga.example/some_endpoint", "https://issuer.fga.example/some_endpoint"),
38+
Arguments.of("https://issuer.fga.example:8080/some_endpoint", "https://issuer.fga.example:8080/some_endpoint")
39+
);
40+
}
2941

30-
@BeforeEach
31-
public void setup() throws FgaInvalidParameterException {
42+
@ParameterizedTest
43+
@MethodSource("issuersTokenEndpoint")
44+
public void exchangeToken(String apiTokenIssuer, String tokenEndpointUrl) throws Exception {
45+
// Given
46+
OAuth2Client oAuth2 = configureClient(apiTokenIssuer);
47+
String expectedPostBody = String.format(
48+
"{\"client_id\":\"%s\",\"client_secret\":\"%s\",\"audience\":\"%s\",\"grant_type\":\"%s\"}",
49+
CLIENT_ID, CLIENT_SECRET, AUDIENCE, GRANT_TYPE);
50+
String responseBody = String.format("{\"access_token\":\"%s\"}", ACCESS_TOKEN);
51+
mockHttpClient.onPost(tokenEndpointUrl).withBody(is(expectedPostBody)).doReturn(200, responseBody);
52+
53+
// When
54+
String result = oAuth2.getAccessToken().get();
55+
56+
// Then
57+
mockHttpClient.verify().post(tokenEndpointUrl).withBody(is(expectedPostBody)).called();
58+
assertEquals(ACCESS_TOKEN, result);
59+
}
60+
61+
private OAuth2Client configureClient(String apiTokenIssuer) {
3262
System.setProperty("HttpRequestAttempt.debug-logging", "enable");
3363
3464
mockHttpClient = new HttpClientMock();
@@ -38,31 +68,14 @@ class OAuth2ClientTest {
3868
.clientId(CLIENT_ID)
3969
.clientSecret(CLIENT_SECRET)
4070
.apiAudience(AUDIENCE)
41-
.apiTokenIssuer(API_TOKEN_ISSUER));
71+
.apiTokenIssuer(apiTokenIssuer));
4272
4373
var configuration = new Configuration().apiUrl("").credentials(credentials);
4474
4575
var apiClient = mock(ApiClient.class);
4676
when(apiClient.getHttpClient()).thenReturn(mockHttpClient);
4777
when(apiClient.getObjectMapper()).thenReturn(mapper);
4878
49-
oAuth2 = new OAuth2Client(configuration, apiClient);
50-
}
51-
52-
@Test
53-
public void exchangeToken() throws Exception {
54-
// Given
55-
String expectedPostBody = String.format(
56-
"{\"client_id\":\"%s\",\"client_secret\":\"%s\",\"audience\":\"%s\",\"grant_type\":\"%s\"}",
57-
CLIENT_ID, CLIENT_SECRET, AUDIENCE, GRANT_TYPE);
58-
String responseBody = String.format("{\"access_token\":\"%s\"}", ACCESS_TOKEN);
59-
mockHttpClient.onPost(POST_URL).withBody(is(expectedPostBody)).doReturn(200, responseBody);
60-
61-
// When
62-
String result = oAuth2.getAccessToken().get();
63-
64-
// Then
65-
mockHttpClient.verify().post(POST_URL).withBody(is(expectedPostBody)).called();
66-
assertEquals(ACCESS_TOKEN, result);
79+
return new OAuth2Client(configuration, apiClient);
6780
}
6881
}

0 commit comments

Comments
 (0)