Skip to content

Commit 8c90170

Browse files
feat(api-client): implement API for configuration auth strategy
1 parent c29004e commit 8c90170

File tree

7 files changed

+152
-21
lines changed

7 files changed

+152
-21
lines changed

modules/api-client/api/api-client.api

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
public final class com/gw2tb/gw2api/client/AuthenticationStrategy : java/lang/Enum {
2+
public static final field HEADER Lcom/gw2tb/gw2api/client/AuthenticationStrategy;
3+
public static final field QUERY Lcom/gw2tb/gw2api/client/AuthenticationStrategy;
4+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
5+
public static fun valueOf (Ljava/lang/String;)Lcom/gw2tb/gw2api/client/AuthenticationStrategy;
6+
public static fun values ()[Lcom/gw2tb/gw2api/client/AuthenticationStrategy;
7+
}
8+
19
public abstract interface class com/gw2tb/gw2api/client/CacheAccess {
210
public abstract fun memoize (Lcom/gw2tb/gw2api/client/Gw2ApiResponse;)V
311
public abstract fun query (Lcom/gw2tb/gw2api/client/Gw2ApiRequest;)Lcom/gw2tb/gw2api/client/Gw2ApiResponse;
@@ -54,18 +62,20 @@ public final class com/gw2tb/gw2api/client/DecodingResultKt {
5462

5563
public final class com/gw2tb/gw2api/client/Gw2ApiClient : java/lang/AutoCloseable {
5664
public fun <init> (Lcom/gw2tb/gw2api/client/internal/http/IHttpClient;Lcom/gw2tb/gw2api/client/Gw2ApiClientBuilder;)V
57-
public fun <init> (Lcom/gw2tb/gw2api/client/internal/http/IHttpClient;Ljava/lang/String;Lcom/gw2tb/gw2api/client/CacheAccess;Lcom/gw2tb/gw2api/client/RateLimiter;Lkotlinx/serialization/json/Json;Ljava/util/List;)V
65+
public fun <init> (Lcom/gw2tb/gw2api/client/internal/http/IHttpClient;Ljava/lang/String;Lcom/gw2tb/gw2api/client/AuthenticationStrategy;Lcom/gw2tb/gw2api/client/CacheAccess;Lcom/gw2tb/gw2api/client/RateLimiter;Lkotlinx/serialization/json/Json;Ljava/util/List;)V
5866
public fun close ()V
5967
public final fun execute (Lcom/gw2tb/gw2api/client/RequestTemplate;)Lcom/gw2tb/gw2api/client/Gw2ApiResponse;
6068
public final fun executeAsync (Lcom/gw2tb/gw2api/client/RequestTemplate;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
6169
}
6270

6371
public final class com/gw2tb/gw2api/client/Gw2ApiClientBuilder {
6472
public final fun configureRequest (Lcom/gw2tb/gw2api/client/RequestConfigurer;)V
73+
public final fun getAuthenticationStrategy ()Lcom/gw2tb/gw2api/client/AuthenticationStrategy;
6574
public final fun getCacheAccess ()Lcom/gw2tb/gw2api/client/CacheAccess;
6675
public final fun getHost ()Ljava/lang/String;
6776
public final fun getJson ()Lkotlinx/serialization/json/Json;
6877
public final fun getRateLimiter ()Lcom/gw2tb/gw2api/client/RateLimiter;
78+
public final fun setAuthenticationStrategy (Lcom/gw2tb/gw2api/client/AuthenticationStrategy;)V
6979
public final fun setCacheAccess (Lcom/gw2tb/gw2api/client/CacheAccess;)V
7080
public final fun setHost (Ljava/lang/String;)V
7181
public final fun setJson (Lkotlinx/serialization/json/Json;)V
@@ -305,6 +315,9 @@ public final class com/gw2tb/gw2api/client/TokenBucketRateLimiter : com/gw2tb/gw
305315
public fun penalize (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
306316
}
307317

318+
public abstract interface annotation class com/gw2tb/gw2api/client/UnsafeQueryAuthentication : java/lang/annotation/Annotation {
319+
}
320+
308321
public abstract class com/gw2tb/gw2api/client/exceptions/ClientValidationException : java/lang/Exception {
309322
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
310323
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2018-2024 Leon Linhart
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
package com.gw2tb.gw2api.client
23+
24+
/**
25+
* An authentication strategy determines how to authenticate requests to the API.
26+
*
27+
* @since 0.8.0
28+
*/
29+
public enum class AuthenticationStrategy {
30+
/**
31+
* Authentication is performed via the `Authorization` header.
32+
*
33+
* @author 0.8.0
34+
*/
35+
HEADER,
36+
37+
/**
38+
* Authentication is performed via the `access_token` query parameter.
39+
*
40+
* **This method is considered unsafe outside of server environments and should be avoided if possible.**
41+
*
42+
* @author 0.8.0
43+
*/
44+
@UnsafeQueryAuthentication
45+
QUERY
46+
}

modules/api-client/src/commonMain/kotlin/com/gw2tb/gw2api/client/Gw2ApiClient.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public fun Gw2ApiClient(httpClient: IHttpClient, block: Gw2ApiClientConfigurer):
5757
public expect class Gw2ApiClient @InternalGw2ApiClientApi constructor(
5858
httpClient: IHttpClient,
5959
host: String,
60+
authenticationStrategy: AuthenticationStrategy,
6061
cacheAccess: CacheAccess?,
6162
rateLimiter: RateLimiter?,
6263
json: Json,

modules/api-client/src/commonMain/kotlin/com/gw2tb/gw2api/client/Gw2ApiClientBuilder.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ public class Gw2ApiClientBuilder internal constructor() {
3939
*/
4040
public var host: String = Gw2ApiClientDefaults.host
4141

42+
/**
43+
* The strategy to use for authentication.
44+
*
45+
* The value defaults to [AuthenticationStrategy.HEADER].
46+
*
47+
* @since 0.8.0
48+
*/
49+
public var authenticationStrategy: AuthenticationStrategy = AuthenticationStrategy.HEADER
50+
4251
/**
4352
* The cache access object to use for caching API responses.
4453
*
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2018-2024 Leon Linhart
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
package com.gw2tb.gw2api.client
23+
24+
/**
25+
* A marker class that is used enforce explicit consent for using [AuthenticationStrategy.QUERY].
26+
*
27+
* @since 0.8.0
28+
*
29+
* @author Leon Linhart
30+
*/
31+
@RequiresOptIn(message = "Authentication via query parameters is considered unsafe outside of server environments and should be avoided if possible.")
32+
public annotation class UnsafeQueryAuthentication

modules/api-client/src/jvmMain/kotlin/com/gw2tb/gw2api/client/Gw2ApiClient.kt

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import kotlinx.serialization.json.Json
3131
public actual class Gw2ApiClient @InternalGw2ApiClientApi actual constructor(
3232
private val httpClient: IHttpClient,
3333
private val host: String,
34+
private val authenticationStrategy: AuthenticationStrategy,
3435
private val cacheAccess: CacheAccess?,
3536
private val rateLimiter: RateLimiter?,
3637
private val json: Json,
@@ -41,6 +42,7 @@ public actual class Gw2ApiClient @InternalGw2ApiClientApi actual constructor(
4142
public actual constructor(httpClient: IHttpClient, builder: Gw2ApiClientBuilder): this(
4243
httpClient = httpClient,
4344
host = builder.host,
45+
authenticationStrategy = builder.authenticationStrategy,
4446
cacheAccess = builder.cacheAccess,
4547
rateLimiter = builder.rateLimiter,
4648
json = builder.json,
@@ -77,19 +79,32 @@ public actual class Gw2ApiClient @InternalGw2ApiClientApi actual constructor(
7779
res
7880
}
7981

82+
val parameters = buildMap {
83+
putAll(template.parameters)
84+
85+
@OptIn(UnsafeQueryAuthentication::class)
86+
if (authenticationStrategy == AuthenticationStrategy.QUERY && template.apiKey != null) {
87+
put("access_token", template.apiKey)
88+
}
89+
90+
if (template.language != null) {
91+
put("lang", template.language.code)
92+
}
93+
}
94+
95+
val headers = buildMap {
96+
putAll(template.headers)
97+
98+
if (authenticationStrategy == AuthenticationStrategy.HEADER && template.apiKey != null) {
99+
put("Authorization", "Bearer ${template.apiKey}")
100+
}
101+
}
102+
80103
val request = Gw2ApiRequest(
81104
baseUrl = host,
82105
path = template.path,
83-
parameters = if (template.language != null) {
84-
template.parameters + ("lang" to template.language.code)
85-
} else {
86-
template.parameters
87-
},
88-
headers = if (template.apiKey != null) {
89-
template.headers + ("Authorization" to "Bearer ${template.apiKey}")
90-
} else {
91-
template.headers
92-
},
106+
parameters = parameters,
107+
headers = headers,
93108
apiKey = template.apiKey,
94109
language = template.language,
95110
serializer = template.serializer

modules/api-client/src/nonJvmMain/kotlin/com/gw2tb/gw2api/client/Gw2ApiClient.kt

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import kotlinx.serialization.json.Json
2929
public actual class Gw2ApiClient @InternalGw2ApiClientApi actual constructor(
3030
private val httpClient: IHttpClient,
3131
private val host: String,
32+
private val authenticationStrategy: AuthenticationStrategy,
3233
private val cacheAccess: CacheAccess?,
3334
private val rateLimiter: RateLimiter?,
3435
private val json: Json,
@@ -39,6 +40,7 @@ public actual class Gw2ApiClient @InternalGw2ApiClientApi actual constructor(
3940
public actual constructor(httpClient: IHttpClient, builder: Gw2ApiClientBuilder): this(
4041
httpClient = httpClient,
4142
host = builder.host,
43+
authenticationStrategy = builder.authenticationStrategy,
4244
cacheAccess = builder.cacheAccess,
4345
rateLimiter = builder.rateLimiter,
4446
json = builder.json,
@@ -56,19 +58,32 @@ public actual class Gw2ApiClient @InternalGw2ApiClientApi actual constructor(
5658
res
5759
}
5860

61+
val parameters = buildMap {
62+
putAll(template.parameters)
63+
64+
@OptIn(UnsafeQueryAuthentication::class)
65+
if (authenticationStrategy == AuthenticationStrategy.QUERY && template.apiKey != null) {
66+
put("access_token", template.apiKey)
67+
}
68+
69+
if (template.language != null) {
70+
put("lang", template.language.code)
71+
}
72+
}
73+
74+
val headers = buildMap {
75+
putAll(template.headers)
76+
77+
if (authenticationStrategy == AuthenticationStrategy.HEADER && template.apiKey != null) {
78+
put("Authorization", "Bearer ${template.apiKey}")
79+
}
80+
}
81+
5982
val request = Gw2ApiRequest(
6083
baseUrl = host,
6184
path = template.path,
62-
parameters = if (template.language != null) {
63-
template.parameters + ("lang" to template.language.code)
64-
} else {
65-
template.parameters
66-
},
67-
headers = if (template.apiKey != null) {
68-
template.headers + ("Authorization" to "Bearer ${template.apiKey}")
69-
} else {
70-
template.headers
71-
},
85+
parameters = parameters,
86+
headers = headers,
7287
apiKey = template.apiKey,
7388
language = template.language,
7489
serializer = template.serializer

0 commit comments

Comments
 (0)