Skip to content

Commit 00da8d6

Browse files
authored
feat(sdk): allow passing OkHttpClient objects (#27)
relates to STACKITSDK-238
1 parent 7e824cf commit 00da8d6

File tree

32 files changed

+902
-200
lines changed

32 files changed

+902
-200
lines changed

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
## Release (2025-XX-XX)
2+
- `core`: [v0.2.0](core/CHANGELOG.md#v020)
3+
- **Feature:** Support for passing custom OkHttpClient objects
4+
- `KeyFlowAuthenticator`: Add new constructors with an `OkHttpClientParam`
5+
- Marked constructors without `OkHttpClient` param as deprecated, use new constructors with `OkHttpClient` instead
6+
- `KeyFlowAuthenticator` implements `okhttp3.Authenticator` interface now
7+
- added method `KeyFlowAuthenticator.authenticate()`
8+
- Marked `KeyFlowInterceptor` class as deprecated, use `KeyFlowAuthenticator` instead
9+
- Marked `SetupAuth` constructors and methods `SetupAuth.init()` and `SetupAuth.getAuthHandler()` as deprecated
10+
- all other methods of `SetupAuth` are marked as `static` now, only these will remain in the future
11+
- `iaas`: [v0.2.0](services/iaas/CHANGELOG.md#v020)
12+
- **Feature:** Support for passing custom OkHttpClient objects
13+
- `ApiClient`
14+
- Added constructors with `OkHttpClient` param (recommended for production use)
15+
- Use new `KeyFlowAuthenticator` `okhttp3.Authenticator` implementation instead of request interceptor for authentication
16+
- `DefaultApi`: Added constructors with `OkHttpClient` param (recommended for production use)
17+
- `IaasApi`: Added constructors with `OkHttpClient` param (recommended for production use)
18+
- `resourcemanager`: [v0.2.0](services/resourcemanager/CHANGELOG.md#v020)
19+
- **Feature:** Support for passing custom OkHttpClient objects
20+
- `ApiClient`
21+
- Added constructors with `OkHttpClient` param (recommended for production use)
22+
- Use new `KeyFlowAuthenticator` `okhttp3.Authenticator` implementation instead of request interceptor for authentication
23+
- `DefaultApi`: Added constructors with `OkHttpClient` param (recommended for production use)
24+
- `ResourceManagerApi`: Added constructors with `OkHttpClient` param (recommended for production use)
25+
- `examples`:
26+
- Add example how to use custom `OkHttpClient` object
27+
128
## Release (2025-09-09)
229
- `core`: [v0.1.0](core/CHANGELOG.md#v010)
330
- Initial onboarding of STACKIT Java SDK core lib

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ Add the dependencies to your project's build file (replace `<SDK_VERSION>` with
5757

5858
## Examples
5959

60-
Examples on services, configuration and authentication possibilities can be found in the [examples folder](https://github.com/stackitcloud/stackit-sdk-java/tree/main/examples).
60+
Examples on services, configuration and authentication possibilities can be found in the [examples folder](/examples).
61+
62+
> [!WARNING]
63+
> For production usage, especially when working with multiple STACKIT SDK modules, consider passing your own `OkHttpClient`
64+
> object (as recommended in the [OkHttpClient lib docs](https://square.github.io/okhttp/3.x/okhttp/index.html?okhttp3/OkHttpClient.html)).
65+
> See our [custom HTTP client example](/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java) for reference.
6166
6267
## Authorization
6368

core/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
1+
## v0.2.0
2+
- **Feature:** Support for passing custom OkHttpClient objects
3+
- `KeyFlowAuthenticator`: Add new constructors with an `OkHttpClientParam`
4+
- Marked constructors without `OkHttpClient` param as deprecated, use new constructors with `OkHttpClient` instead
5+
- `KeyFlowAuthenticator` implements `okhttp3.Authenticator` interface now
6+
- added method `KeyFlowAuthenticator.authenticate()`
7+
- Marked `KeyFlowInterceptor` class as deprecated, use `KeyFlowAuthenticator` instead
8+
- Marked `SetupAuth` constructors and methods `SetupAuth.init()` and `SetupAuth.getAuthHandler()` as deprecated
9+
- all other methods of `SetupAuth` are marked as `static` now, only these will remain in the future
10+
111
## v0.1.0
212
- Initial onboarding of STACKIT Java SDK core lib

core/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.0
1+
0.2.0

core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java

Lines changed: 106 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package cloud.stackit.sdk.core;
22

3+
import cloud.stackit.sdk.core.auth.SetupAuth;
34
import cloud.stackit.sdk.core.config.CoreConfiguration;
45
import cloud.stackit.sdk.core.config.EnvironmentVariables;
56
import cloud.stackit.sdk.core.exception.ApiException;
@@ -23,16 +24,18 @@
2324
import java.util.UUID;
2425
import java.util.concurrent.TimeUnit;
2526
import okhttp3.*;
27+
import org.jetbrains.annotations.NotNull;
2628

27-
/** KeyFlowAuthenticator handles the Key Flow Authentication based on the Service Account Key. */
28-
public class KeyFlowAuthenticator {
29-
private final String REFRESH_TOKEN = "refresh_token";
30-
private final String ASSERTION = "assertion";
31-
private final String DEFAULT_TOKEN_ENDPOINT = "https://service-account.api.stackit.cloud/token";
32-
private final long DEFAULT_TOKEN_LEEWAY = 60;
33-
private final int CONNECT_TIMEOUT = 10;
34-
private final int WRITE_TIMEOUT = 10;
35-
private final int READ_TIMEOUT = 10;
29+
/* KeyFlowAuthenticator handles the Key Flow Authentication based on the Service Account Key. */
30+
public class KeyFlowAuthenticator implements Authenticator {
31+
private static final String REFRESH_TOKEN = "refresh_token";
32+
private static final String ASSERTION = "assertion";
33+
private static final String DEFAULT_TOKEN_ENDPOINT =
34+
"https://service-account.api.stackit.cloud/token";
35+
private static final long DEFAULT_TOKEN_LEEWAY = 60;
36+
private static final int CONNECT_TIMEOUT = 10;
37+
private static final int WRITE_TIMEOUT = 10;
38+
private static final int READ_TIMEOUT = 10;
3639

3740
private final OkHttpClient httpClient;
3841
private final ServiceAccountKey saKey;
@@ -41,6 +44,100 @@ public class KeyFlowAuthenticator {
4144
private final String tokenUrl;
4245
private long tokenLeewayInSeconds = DEFAULT_TOKEN_LEEWAY;
4346

47+
/**
48+
* Creates the initial service account and refreshes expired access token.
49+
*
50+
* @deprecated use constructor with OkHttpClient instead to prevent resource leaks. Will be
51+
* removed in April 2026.
52+
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
53+
* @param saKey Service Account Key, which should be used for the authentication
54+
*/
55+
@Deprecated
56+
public KeyFlowAuthenticator(CoreConfiguration cfg, ServiceAccountKey saKey) {
57+
this(new OkHttpClient(), cfg, saKey, new EnvironmentVariables());
58+
}
59+
60+
/**
61+
* Creates the initial service account and refreshes expired access token.
62+
*
63+
* @deprecated use constructor with OkHttpClient instead to prevent resource leaks. Will be
64+
* removed in April 2026.
65+
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
66+
* @param saKey Service Account Key, which should be used for the authentication
67+
*/
68+
@Deprecated
69+
public KeyFlowAuthenticator(
70+
CoreConfiguration cfg,
71+
ServiceAccountKey saKey,
72+
EnvironmentVariables environmentVariables) {
73+
this(new OkHttpClient(), cfg, saKey, environmentVariables);
74+
}
75+
76+
/**
77+
* Creates the initial service account and refreshes expired access token.
78+
*
79+
* @param httpClient OkHttpClient object
80+
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
81+
*/
82+
public KeyFlowAuthenticator(OkHttpClient httpClient, CoreConfiguration cfg) throws IOException {
83+
this(httpClient, cfg, SetupAuth.setupKeyFlow(cfg), new EnvironmentVariables());
84+
}
85+
86+
/**
87+
* Creates the initial service account and refreshes expired access token.
88+
*
89+
* @param httpClient OkHttpClient object
90+
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
91+
* @param saKey Service Account Key, which should be used for the authentication
92+
*/
93+
public KeyFlowAuthenticator(
94+
OkHttpClient httpClient, CoreConfiguration cfg, ServiceAccountKey saKey) {
95+
this(httpClient, cfg, saKey, new EnvironmentVariables());
96+
}
97+
98+
protected KeyFlowAuthenticator(
99+
OkHttpClient httpClient,
100+
CoreConfiguration cfg,
101+
ServiceAccountKey saKey,
102+
EnvironmentVariables environmentVariables) {
103+
this.saKey = saKey;
104+
this.gson = new Gson();
105+
this.httpClient =
106+
httpClient
107+
.newBuilder()
108+
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
109+
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
110+
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
111+
.build();
112+
113+
if (Utils.isStringSet(cfg.getTokenCustomUrl())) {
114+
this.tokenUrl = cfg.getTokenCustomUrl();
115+
} else if (Utils.isStringSet(environmentVariables.getStackitTokenBaseurl())) {
116+
this.tokenUrl = environmentVariables.getStackitTokenBaseurl();
117+
} else {
118+
this.tokenUrl = DEFAULT_TOKEN_ENDPOINT;
119+
}
120+
if (cfg.getTokenExpirationLeeway() != null && cfg.getTokenExpirationLeeway() > 0) {
121+
this.tokenLeewayInSeconds = cfg.getTokenExpirationLeeway();
122+
}
123+
}
124+
125+
@Override
126+
public Request authenticate(Route route, @NotNull Response response) throws IOException {
127+
String accessToken;
128+
try {
129+
accessToken = getAccessToken();
130+
} catch (ApiException | InvalidKeySpecException e) {
131+
throw new RuntimeException(e);
132+
}
133+
134+
// Return a new request with the refreshed token
135+
return response.request()
136+
.newBuilder()
137+
.header("Authorization", "Bearer " + accessToken)
138+
.build();
139+
}
140+
44141
protected static class KeyFlowTokenResponse {
45142
@SerializedName("access_token")
46143
private String accessToken;
@@ -79,45 +176,6 @@ protected String getAccessToken() {
79176
}
80177
}
81178

82-
public KeyFlowAuthenticator(CoreConfiguration cfg, ServiceAccountKey saKey) {
83-
this(cfg, saKey, null);
84-
}
85-
86-
/**
87-
* Creates the initial service account and refreshes expired access token.
88-
*
89-
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
90-
* @param saKey Service Account Key, which should be used for the authentication
91-
*/
92-
public KeyFlowAuthenticator(
93-
CoreConfiguration cfg,
94-
ServiceAccountKey saKey,
95-
EnvironmentVariables environmentVariables) {
96-
this.saKey = saKey;
97-
this.gson = new Gson();
98-
this.httpClient =
99-
new OkHttpClient.Builder()
100-
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
101-
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
102-
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
103-
.build();
104-
105-
if (environmentVariables == null) {
106-
environmentVariables = new EnvironmentVariables();
107-
}
108-
109-
if (Utils.isStringSet(cfg.getTokenCustomUrl())) {
110-
this.tokenUrl = cfg.getTokenCustomUrl();
111-
} else if (Utils.isStringSet(environmentVariables.getStackitTokenBaseurl())) {
112-
this.tokenUrl = environmentVariables.getStackitTokenBaseurl();
113-
} else {
114-
this.tokenUrl = DEFAULT_TOKEN_ENDPOINT;
115-
}
116-
if (cfg.getTokenExpirationLeeway() != null && cfg.getTokenExpirationLeeway() > 0) {
117-
this.tokenLeewayInSeconds = cfg.getTokenExpirationLeeway();
118-
}
119-
}
120-
121179
/**
122180
* Returns access token. If the token is expired it creates a new token.
123181
*

core/src/main/java/cloud/stackit/sdk/core/KeyFlowInterceptor.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@
88
import okhttp3.Response;
99
import org.jetbrains.annotations.NotNull;
1010

11+
@Deprecated
12+
/*
13+
* @deprecated use KeyFlowAuthenticator instead. Will be removed in April 2026.
14+
* */
1115
public class KeyFlowInterceptor implements Interceptor {
1216
private final KeyFlowAuthenticator authenticator;
1317

18+
@Deprecated
19+
/*
20+
* @deprecated use KeyFlowAuthenticator instead. Will be removed in April 2026.
21+
* */
1422
public KeyFlowInterceptor(KeyFlowAuthenticator authenticator) {
1523
this.authenticator = authenticator;
1624
}
1725

1826
@NotNull @Override
27+
@Deprecated
28+
/*
29+
* @deprecated use KeyFlowAuthenticator instead. Will be removed in April 2026.
30+
* */
1931
public Response intercept(Chain chain) throws IOException {
2032

2133
Request originalRequest = chain.request();

0 commit comments

Comments
 (0)