Skip to content

feat(kotlin-client): support dynamic auth credentials for okhttp client (#23835)#23836

Open
manujell73 wants to merge 1 commit into
OpenAPITools:masterfrom
manujell73:kotlin-client-dynamic-auth-support
Open

feat(kotlin-client): support dynamic auth credentials for okhttp client (#23835)#23836
manujell73 wants to merge 1 commit into
OpenAPITools:masterfrom
manujell73:kotlin-client-dynamic-auth-support

Conversation

@manujell73
Copy link
Copy Markdown

@manujell73 manujell73 commented May 20, 2026

resolves #23835

This change adds dynamic credential/token provider support to Kotlin jvm-okhttp clients so auth values can be resolved at request time (instead of only using static ApiClient fields).

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • File the PR against the correct branch: master (upcoming 7.x.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR solves a reported issue, reference it using GitHub's linking syntax (e.g., having "fixes #123" present in the PR description)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Kotlin comittee:
@karismann (2019/03) @Zomzog (2019/04) @andrewemery (2019/10) @4brunu (2019/11) @yutaka0m (2020/03) @stefankoppier (2022/06) @e5l (2024/10) @dennisameling (2026/02)


Summary by cubic

Adds dynamic auth providers to Kotlin JVM okhttp clients so credentials/tokens are resolved per request. This enables rotating tokens and multi-tenant auth without rebuilding the client.

  • New Features
    • Introduced userCredentialsProvider and accessTokenProvider callbacks on ApiClient for JVM okhttp clients; invoked at request time to set the Authorization header when missing.
    • Supports Basic, Bearer, and OAuth schemes.
    • Backwards compatible: providers default to existing static fields; existing code keeps working.
    • Updated generated docs and samples to show both static and dynamic auth setup.

Written for commit 22fe45d. Summary will update on new commits. Review in cubic

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 issues found across 61 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/client/others/kotlin-jvm-okhttp-path-comments/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt">

<violation number="1" location="samples/client/others/kotlin-jvm-okhttp-path-comments/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt:123">
P1: Dynamic auth providers are not injectable: `accessTokenProvider` and `userCredentialsProvider` are `val` (final) instance properties that cannot be overridden or reassigned, and are not constructor parameters. Generated-client callers cannot supply custom token sources, so the provider always falls back to the static companion-object fields and the dynamic-auth feature is effectively inert.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache:88">
P1: Dynamic auth docs configure provider on a throwaway instance, causing silent auth failure when followed</violation>
</file>

<file name="samples/client/echo_api/kotlin-jvm-spring-3-webclient/docs/AuthApi.md">

<violation number="1" location="samples/client/echo_api/kotlin-jvm-spring-3-webclient/docs/AuthApi.md:55">
P2: Webclient sample docs advertise dynamic auth provider APIs that are not implemented in the webclient generated code</violation>
</file>

<file name="samples/client/petstore/kotlin-jackson/docs/PetApi.md">

<violation number="1" location="samples/client/petstore/kotlin-jackson/docs/PetApi.md:60">
P1: Dynamic auth documentation configures accessTokenProvider on a newly created, discarded PetApi instance rather than the apiInstance used in the preceding request example. Because accessTokenProvider is an instance property in the generated ApiClient base class, this pattern will not apply credentials to the actual request instance, causing auth headers to be missing.</violation>
</file>

<file name="samples/client/petstore/kotlin-jvm-ktor-gson/docs/FakeApi.md">

<violation number="1" location="samples/client/petstore/kotlin-jvm-ktor-gson/docs/FakeApi.md:105">
P2: Ktor sample docs advertise `accessTokenProvider` which does not exist in the generated Ktor client code, causing a generator/docs mismatch.</violation>
</file>

<file name="samples/client/others/kotlin-jvm-okhttp-non-ascii-headers/docs/PetApi.md">

<violation number="1" location="samples/client/others/kotlin-jvm-okhttp-non-ascii-headers/docs/PetApi.md:63">
P1: Dynamic auth documentation configures `accessTokenProvider` on a throwaway `PetApi()` instance instead of the `apiInstance` used in the request example. Since `accessTokenProvider` is an instance property of `ApiClient`, users following these docs will not have their dynamic credentials applied to actual requests.</violation>
</file>

<file name="samples/client/petstore/kotlin-jvm-vertx-moshi/docs/PetApi.md">

<violation number="1" location="samples/client/petstore/kotlin-jvm-vertx-moshi/docs/PetApi.md:63">
P1: Cross-generator documentation mismatch: `kotlin-jvm-vertx-moshi` docs now reference `accessTokenProvider`, which is only implemented in the `jvm-okhttp` library template. The shared `api_doc.mustache` was updated for okhttp dynamic credentials, but vertx-moshi's generated `ApiClient.kt` does not have this property, so the documented example code will not compile.</violation>
</file>

<file name="samples/client/petstore/kotlin-allOf-discriminator-kotlinx-serialization/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt">

<violation number="1" location="samples/client/petstore/kotlin-allOf-discriminator-kotlinx-serialization/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt:123">
P2: Dynamic auth providers are hardcoded `val` with no configuration path, making the advertised per-instance provider support unusable. The `userCredentialsProvider` and `accessTokenProvider` default to reading static companion fields and cannot be overridden or injected.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

}

val userCredentialsProvider: () -> Pair<String?, String?> = { username to password }
val accessTokenProvider: () -> String? = { accessToken }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Dynamic auth providers are not injectable: accessTokenProvider and userCredentialsProvider are val (final) instance properties that cannot be overridden or reassigned, and are not constructor parameters. Generated-client callers cannot supply custom token sources, so the provider always falls back to the static companion-object fields and the dynamic-auth feature is effectively inert.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/others/kotlin-jvm-okhttp-path-comments/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt, line 123:

<comment>Dynamic auth providers are not injectable: `accessTokenProvider` and `userCredentialsProvider` are `val` (final) instance properties that cannot be overridden or reassigned, and are not constructor parameters. Generated-client callers cannot supply custom token sources, so the provider always falls back to the static companion-object fields and the dynamic-auth feature is effectively inert.</comment>

<file context>
@@ -119,6 +119,9 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
     }
 
+    val userCredentialsProvider: () -> Pair<String?, String?> = { username to password }
+    val accessTokenProvider: () -> String? = { accessToken }
+
     /**
</file context>

```
Configure {{name}} dynamically:
```kotlin
{{{classname}}}().accessTokenProvider = { "" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Dynamic auth docs configure provider on a throwaway instance, causing silent auth failure when followed

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/kotlin-client/api_doc.mustache, line 88:

<comment>Dynamic auth docs configure provider on a throwaway instance, causing silent auth failure when followed</comment>

<file context>
@@ -68,18 +68,36 @@ Configure {{name}}:
+```
+Configure {{name}} dynamically:
+```kotlin
+{{{classname}}}().accessTokenProvider = { "" }
+```
 {{/isBasicBearer}}
</file context>

```
Configure petstore_auth dynamically:
```kotlin
PetApi().accessTokenProvider = { "" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Dynamic auth documentation configures accessTokenProvider on a newly created, discarded PetApi instance rather than the apiInstance used in the preceding request example. Because accessTokenProvider is an instance property in the generated ApiClient base class, this pattern will not apply credentials to the actual request instance, causing auth headers to be missing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/kotlin-jackson/docs/PetApi.md, line 60:

<comment>Dynamic auth documentation configures accessTokenProvider on a newly created, discarded PetApi instance rather than the apiInstance used in the preceding request example. Because accessTokenProvider is an instance property in the generated ApiClient base class, this pattern will not apply credentials to the actual request instance, causing auth headers to be missing.</comment>

<file context>
@@ -51,8 +51,14 @@ null (empty response body)
+```
+Configure petstore_auth dynamically:
+```kotlin
+PetApi().accessTokenProvider = { "" }
+```
 
</file context>

```
Configure petstore_auth dynamically:
```kotlin
PetApi().accessTokenProvider = { "" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Dynamic auth documentation configures accessTokenProvider on a throwaway PetApi() instance instead of the apiInstance used in the request example. Since accessTokenProvider is an instance property of ApiClient, users following these docs will not have their dynamic credentials applied to actual requests.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/others/kotlin-jvm-okhttp-non-ascii-headers/docs/PetApi.md, line 63:

<comment>Dynamic auth documentation configures `accessTokenProvider` on a throwaway `PetApi()` instance instead of the `apiInstance` used in the request example. Since `accessTokenProvider` is an instance property of `ApiClient`, users following these docs will not have their dynamic credentials applied to actual requests.</comment>

<file context>
@@ -54,8 +54,14 @@ try {
+```
+Configure petstore_auth dynamically:
+```kotlin
+PetApi().accessTokenProvider = { "" }
+```
 
</file context>
Suggested change
PetApi().accessTokenProvider = { "" }
apiInstance.accessTokenProvider = { "" }

```
Configure petstore_auth dynamically:
```kotlin
PetApi().accessTokenProvider = { "" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Cross-generator documentation mismatch: kotlin-jvm-vertx-moshi docs now reference accessTokenProvider, which is only implemented in the jvm-okhttp library template. The shared api_doc.mustache was updated for okhttp dynamic credentials, but vertx-moshi's generated ApiClient.kt does not have this property, so the documented example code will not compile.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/kotlin-jvm-vertx-moshi/docs/PetApi.md, line 63:

<comment>Cross-generator documentation mismatch: `kotlin-jvm-vertx-moshi` docs now reference `accessTokenProvider`, which is only implemented in the `jvm-okhttp` library template. The shared `api_doc.mustache` was updated for okhttp dynamic credentials, but vertx-moshi's generated `ApiClient.kt` does not have this property, so the documented example code will not compile.</comment>

<file context>
@@ -54,8 +54,14 @@ try {
+```
+Configure petstore_auth dynamically:
+```kotlin
+PetApi().accessTokenProvider = { "" }
+```
 
</file context>

```
Configure http_auth dynamically:
```kotlin
AuthApi().userCredentialProvider = { "user" to "pass" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Webclient sample docs advertise dynamic auth provider APIs that are not implemented in the webclient generated code

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/echo_api/kotlin-jvm-spring-3-webclient/docs/AuthApi.md, line 55:

<comment>Webclient sample docs advertise dynamic auth provider APIs that are not implemented in the webclient generated code</comment>

<file context>
@@ -45,9 +45,15 @@ This endpoint does not need any parameter.
+```
+Configure http_auth dynamically:
+```kotlin
+AuthApi().userCredentialProvider = { "user" to "pass" }
+```
 
</file context>

```
Configure petstore_auth dynamically:
```kotlin
FakeApi().accessTokenProvider = { "" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Ktor sample docs advertise accessTokenProvider which does not exist in the generated Ktor client code, causing a generator/docs mismatch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/kotlin-jvm-ktor-gson/docs/FakeApi.md, line 105:

<comment>Ktor sample docs advertise `accessTokenProvider` which does not exist in the generated Ktor client code, causing a generator/docs mismatch.</comment>

<file context>
@@ -96,8 +96,14 @@ null (empty response body)
+```
+Configure petstore_auth dynamically:
+```kotlin
+FakeApi().accessTokenProvider = { "" }
+```
 
</file context>

val builder: OkHttpClient.Builder = OkHttpClient.Builder()
}

val userCredentialsProvider: () -> Pair<String?, String?> = { username to password }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Dynamic auth providers are hardcoded val with no configuration path, making the advertised per-instance provider support unusable. The userCredentialsProvider and accessTokenProvider default to reading static companion fields and cannot be overridden or injected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/kotlin-allOf-discriminator-kotlinx-serialization/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt, line 123:

<comment>Dynamic auth providers are hardcoded `val` with no configuration path, making the advertised per-instance provider support unusable. The `userCredentialsProvider` and `accessTokenProvider` default to reading static companion fields and cannot be overridden or injected.</comment>

<file context>
@@ -120,6 +120,9 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
         val builder: OkHttpClient.Builder = OkHttpClient.Builder()
     }
 
+    val userCredentialsProvider: () -> Pair<String?, String?> = { username to password }
+    val accessTokenProvider: () -> String? = { accessToken }
+
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REQ][Kotlin] Support dynamic auth context for generated okhttp client

1 participant