11package cloud .stackit .sdk .core ;
22
3+ import cloud .stackit .sdk .core .auth .SetupAuth ;
34import cloud .stackit .sdk .core .config .CoreConfiguration ;
45import cloud .stackit .sdk .core .config .EnvironmentVariables ;
56import cloud .stackit .sdk .core .exception .ApiException ;
2324import java .util .UUID ;
2425import java .util .concurrent .TimeUnit ;
2526import 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 *
0 commit comments