Skip to content

Commit c258a39

Browse files
committed
grpc: Add documentation
1 parent 4c967e0 commit c258a39

File tree

5 files changed

+397
-12
lines changed

5 files changed

+397
-12
lines changed

grpc/grpc-client/src/commonMain/kotlin/kotlinx/rpc/grpc/client/GrpcCallCredentials.kt

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,153 @@ package kotlinx.rpc.grpc.client
66

77
import kotlinx.rpc.grpc.GrpcMetadata
88

9+
/**
10+
* Provides per-call authentication credentials for gRPC calls.
11+
*
12+
* Call credentials are used to attach authentication information (such as tokens, API keys, or signatures)
13+
* to individual gRPC calls through metadata headers. Unlike client credentials, which establish
14+
* the transport security layer (e.g., TLS), call credentials operate at the application layer
15+
* and can be dynamically generated for each request.
16+
*
17+
* ## Usage
18+
*
19+
* Implement this interface to create custom authentication mechanisms:
20+
*
21+
* ```kotlin
22+
* class BearerTokenCredentials(private val token: String) : GrpcCallCredentials {
23+
* override suspend fun GrpcMetadata.applyOnMetadata(callOptions: GrpcCallOptions) {
24+
* append("Authorization", "Bearer $token")
25+
* }
26+
* }
27+
* ```
28+
*
29+
* Credentials can be combined using the [plus] operator or [combine] function:
30+
*
31+
* ```kotlin
32+
* val credentials = TlsClientCredentials(...) + BearerTokenCredentials("my-token")
33+
* ```
34+
*
35+
* ## Transport Security
36+
*
37+
* By default, call credentials require transport security (TLS) to prevent credential leakage.
38+
* Override [requiresTransportSecurity] to `false` only for testing or non-production environments.
39+
*
40+
* @see applyOnMetadata
41+
* @see requiresTransportSecurity
42+
* @see plus
43+
* @see combine
44+
*/
945
public interface GrpcCallCredentials {
1046

47+
/**
48+
* Applies authentication metadata to the gRPC call.
49+
*
50+
* This method is invoked before each gRPC call to add authentication headers or metadata.
51+
* Implementations should append the necessary authentication information to the [GrpcMetadata] receiver.
52+
*
53+
* The method is suspending to allow asynchronous token retrieval or refresh operations,
54+
* such as fetching tokens from secure storage or performing OAuth token exchanges.
55+
*
56+
* ## Examples
57+
*
58+
* Adding a bearer token:
59+
* ```kotlin
60+
* override suspend fun GrpcMetadata.applyOnMetadata(callOptions: GrpcCallOptions) {
61+
* append("Authorization", "Bearer $token")
62+
* }
63+
* ```
64+
*
65+
* Throwing a [kotlinx.rpc.grpc.StatusException] to fail the call:
66+
* ```kotlin
67+
* override suspend fun GrpcMetadata.applyOnMetadata(callOptions: GrpcCallOptions) {
68+
* if (!isValid) {
69+
* throw StatusException(Status(StatusCode.UNAUTHENTICATED, "Invalid credentials"))
70+
* }
71+
* append("Authorization", "Bearer $token")
72+
* }
73+
* ```
74+
*
75+
* @param callOptions The options for the current call, providing context and configuration.
76+
* @receiver The metadata to which authentication information should be added.
77+
* @throws kotlinx.rpc.grpc.StatusException to abort the call with a specific gRPC status.
78+
*/
1179
public suspend fun GrpcMetadata.applyOnMetadata(callOptions: GrpcCallOptions)
1280

81+
/**
82+
* Indicates whether this credential requires transport security (TLS).
83+
*
84+
* When `true` (the default), the credential will only be applied to calls over secure transports.
85+
* If transport security is not present, the call will fail with `UNAUTHENTICATED`.
86+
*
87+
* Set to `false` only for credentials that are safe to send over insecure connections,
88+
* such as in testing environments or for non-sensitive authentication mechanisms.
89+
*
90+
* @return `true` if transport security is required, `false` otherwise.
91+
*/
1392
public val requiresTransportSecurity: Boolean
1493
get() = true
1594
}
1695

96+
/**
97+
* Combines two call credentials into a single credential that applies both.
98+
*
99+
* The resulting credential will apply both sets of credentials in order, allowing
100+
* multiple authentication mechanisms to be used simultaneously. For example,
101+
* combining channel credentials with call credentials, or applying multiple
102+
* authentication headers to the same call.
103+
*
104+
* The combined credential requires transport security if either of the original
105+
* credentials requires it.
106+
*
107+
* ## Example
108+
*
109+
* ```kotlin
110+
* val tlsCreds = TlsClientCredentials { ... }
111+
* val bearerToken = BearerTokenCredentials("my-token")
112+
* val combined = tlsCreds + bearerToken
113+
* ```
114+
*
115+
* Multiple credentials can be chained:
116+
* ```kotlin
117+
* val combined = creds1 + creds2 + creds3
118+
* ```
119+
*
120+
* @param other The credential to combine with this one.
121+
* @return A new credential that applies both credentials.
122+
* @see combine
123+
*/
17124
public operator fun GrpcCallCredentials.plus(other: GrpcCallCredentials): GrpcCallCredentials {
18125
return CombinedCallCredentials(this, other)
19126
}
20127

128+
/**
129+
* Combines two call credentials into a single credential that applies both.
130+
*
131+
* This is an alias for the [plus] operator, providing a more explicit method name
132+
* for combining credentials.
133+
*
134+
* @param other The credential to combine with this one.
135+
* @return A new credential that applies both credentials.
136+
* @see plus
137+
*/
21138
public fun GrpcCallCredentials.combine(other: GrpcCallCredentials): GrpcCallCredentials = this + other
22139

140+
/**
141+
* A call credential that performs no authentication.
142+
*
143+
* This is useful as a no-op placeholder or for disabling authentication in specific scenarios.
144+
* Since it performs no authentication, it does not require transport security.
145+
*
146+
* ## Example
147+
*
148+
* ```kotlin
149+
* val credentials = if (useAuth) {
150+
* BearerTokenCredentials(token)
151+
* } else {
152+
* EmptyCallCredentials
153+
* }
154+
* ```
155+
*/
23156
public object EmptyCallCredentials : GrpcCallCredentials {
24157
override suspend fun GrpcMetadata.applyOnMetadata(callOptions: GrpcCallOptions) {
25158
// do nothing
@@ -43,5 +176,4 @@ internal class CombinedCallCredentials(
43176
}
44177

45178
override val requiresTransportSecurity: Boolean = first.requiresTransportSecurity || second.requiresTransportSecurity
46-
47179
}

grpc/grpc-client/src/commonMain/kotlin/kotlinx/rpc/grpc/client/GrpcCallOptions.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,48 @@ public class GrpcCallOptions {
5050
*/
5151
public var compression: GrpcCompression = GrpcCompression.None
5252

53+
/**
54+
* Per-call authentication credentials to apply to this RPC.
55+
*
56+
* Call credentials allow dynamic, per-request authentication by adding metadata headers
57+
* such as bearer tokens, API keys, or custom authentication information.
58+
*
59+
* ## Default Behavior
60+
* Defaults to [EmptyCallCredentials], which attaches no authentication headers.
61+
*
62+
* ## Usage Patterns
63+
*
64+
* ### Setting in Client Interceptors
65+
* Call credentials can be dynamically added or modified in client interceptors:
66+
*
67+
* ```kotlin
68+
* val client = GrpcClient("example.com", 443) {
69+
* interceptors {
70+
* clientInterceptor {
71+
* callOptions.callCredentials += BearerTokenCredentials(getToken())
72+
* proceed(it)
73+
* }
74+
* }
75+
* }
76+
* ```
77+
*
78+
* ### Combining Multiple Credentials
79+
* Multiple call credentials can be combined using the `+` operator:
80+
*
81+
* ```kotlin
82+
* callOptions.callCredentials = bearerToken + apiKey
83+
* // or incrementally:
84+
* callOptions.callCredentials += additionalCredential
85+
* ```
86+
*
87+
* ### Transport Security
88+
* If any call credential requires transport security ([GrpcCallCredentials.requiresTransportSecurity]),
89+
* the call will fail with [kotlinx.rpc.grpc.StatusCode.UNAUTHENTICATED] unless the channel
90+
* is configured with TLS credentials (which is the default, except if the client uses `plaintext()`).
91+
*
92+
* @see GrpcCallCredentials
93+
* @see EmptyCallCredentials
94+
* @see GrpcCallCredentials.plus
95+
*/
5396
public var callCredentials: GrpcCallCredentials = EmptyCallCredentials
5497
}

0 commit comments

Comments
 (0)