From 079eaf2c197caa88c21f18fb8034b7d77825412e Mon Sep 17 00:00:00 2001 From: John Mitsch Date: Tue, 23 Jun 2026 14:41:08 -0400 Subject: [PATCH] fix(admin)!: make kid required for create_jwt The kid (key identifier) is required when creating a JWT on an endpoint via POST /endpoints/:id/security/jwts. Reflect that in the typed surface so callers get a compile/type error instead of a server-side rejection. - core: CreateJwtRequest.kid is now String (was Option) - python: create_jwt(id, kid, public_key=None, name=None) - node: CreateJwtRequest.kid is now required - ruby: kid validated via hash_require_string; rbs updated --- crates/core/README.md | 2 +- crates/core/examples/admin_e2e.rs | 2 +- crates/core/src/admin/endpoint_security.rs | 3 +-- crates/python/src/lib.rs | 4 ++-- crates/ruby/src/lib.rs | 2 +- npm/README.md | 2 +- npm/index.d.ts | 2 +- python/README.md | 2 +- python/quicknode_sdk/_core/__init__.pyi | 6 +++--- ruby/README.md | 2 +- ruby/sig/quicknode_sdk.rbs | 2 +- 11 files changed, 14 insertions(+), 15 deletions(-) diff --git a/crates/core/README.md b/crates/core/README.md index d1e0f97..d15f5b0 100644 --- a/crates/core/README.md +++ b/crates/core/README.md @@ -659,7 +659,7 @@ qn.admin.delete_domain_mask("ep-123", "dm-1").await?; Configures JWT validation on an endpoint. -**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, optional), `name` (string, optional). +**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, required), `name` (string, optional). **Returns**: nothing. diff --git a/crates/core/examples/admin_e2e.rs b/crates/core/examples/admin_e2e.rs index 6a76e2a..0ab7302 100644 --- a/crates/core/examples/admin_e2e.rs +++ b/crates/core/examples/admin_e2e.rs @@ -455,7 +455,7 @@ async fn main() { public_key: Some( "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER\n-----END PUBLIC KEY-----".to_string(), ), - kid: Some("kid1".to_string()), + kid: "kid1".to_string(), name: Some("example-jwt".to_string()), }, ) diff --git a/crates/core/src/admin/endpoint_security.rs b/crates/core/src/admin/endpoint_security.rs index ee02edf..30241f2 100644 --- a/crates/core/src/admin/endpoint_security.rs +++ b/crates/core/src/admin/endpoint_security.rs @@ -143,8 +143,7 @@ pub struct CreateJwtRequest { #[serde(skip_serializing_if = "Option::is_none")] pub public_key: Option, /// Key identifier (`kid`) embedded in JWT headers. - #[serde(skip_serializing_if = "Option::is_none")] - pub kid: Option, + pub kid: String, /// Human-readable name for the JWT configuration. #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, diff --git a/crates/python/src/lib.rs b/crates/python/src/lib.rs index 87bcdf1..70950d3 100644 --- a/crates/python/src/lib.rs +++ b/crates/python/src/lib.rs @@ -667,14 +667,14 @@ impl AdminApiClient { /// Creates a new JWT for endpoint authentication. Accepts a public key, /// key id (`kid`), and token name. - #[pyo3(signature = (id, public_key=None, kid=None, name=None))] + #[pyo3(signature = (id, kid, public_key=None, name=None))] #[gen_stub(override_return_type(type_repr = "typing.Coroutine[typing.Any, typing.Any, None]"))] fn create_jwt<'py>( &self, py: Python<'py>, id: String, + kid: String, public_key: Option, - kid: Option, name: Option, ) -> PyResult> { let client = self.inner.clone(); diff --git a/crates/ruby/src/lib.rs b/crates/ruby/src/lib.rs index ed6ed14..4ced74a 100644 --- a/crates/ruby/src/lib.rs +++ b/crates/ruby/src/lib.rs @@ -671,7 +671,7 @@ impl AdminApiClient { let id = hash_require_string(&opts, "id")?; let params = core::admin::CreateJwtRequest { public_key: hash_get_string(&opts, "public_key")?, - kid: hash_get_string(&opts, "kid")?, + kid: hash_require_string(&opts, "kid")?, name: hash_get_string(&opts, "name")?, }; runtime() diff --git a/npm/README.md b/npm/README.md index d37f472..12afdf7 100644 --- a/npm/README.md +++ b/npm/README.md @@ -637,7 +637,7 @@ await qn.admin.deleteDomainMask("ep-123", "dm-1"); Configures JWT validation on an endpoint. -**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, optional), `name` (string, optional). +**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, required), `name` (string, optional). **Returns**: nothing. diff --git a/npm/index.d.ts b/npm/index.d.ts index 8c06113..13dd1fe 100644 --- a/npm/index.d.ts +++ b/npm/index.d.ts @@ -242,7 +242,7 @@ export interface CreateJwtRequest { /** Public key used to verify signed JWTs. */ publicKey?: string /** Key identifier (`kid`) embedded in JWT headers. */ - kid?: string + kid: string /** Human-readable name for the JWT configuration. */ name?: string } diff --git a/python/README.md b/python/README.md index 204d2dd..c26a39f 100644 --- a/python/README.md +++ b/python/README.md @@ -640,7 +640,7 @@ await qn.admin.delete_domain_mask("ep-123", "dm-1") Configures JWT validation on an endpoint. -**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, optional), `name` (string, optional). +**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, required), `name` (string, optional). **Returns**: nothing. diff --git a/python/quicknode_sdk/_core/__init__.pyi b/python/quicknode_sdk/_core/__init__.pyi index 458afcb..318a1f6 100644 --- a/python/quicknode_sdk/_core/__init__.pyi +++ b/python/quicknode_sdk/_core/__init__.pyi @@ -412,7 +412,7 @@ class AdminApiClient: r""" Removes a domain mask from an endpoint by domain mask id. """ - def create_jwt(self, id: builtins.str, public_key: typing.Optional[builtins.str] = None, kid: typing.Optional[builtins.str] = None, name: typing.Optional[builtins.str] = None) -> typing.Coroutine[typing.Any, typing.Any, None]: + def create_jwt(self, id: builtins.str, kid: builtins.str, public_key: typing.Optional[builtins.str] = None, name: typing.Optional[builtins.str] = None) -> typing.Coroutine[typing.Any, typing.Any, None]: r""" Creates a new JWT for endpoint authentication. Accepts a public key, key id (`kid`), and token name. @@ -1319,12 +1319,12 @@ class CreateJwtRequest: Public key used to verify signed JWTs. """ @property - def kid(self) -> typing.Optional[builtins.str]: + def kid(self) -> builtins.str: r""" Key identifier (`kid`) embedded in JWT headers. """ @kid.setter - def kid(self, value: typing.Optional[builtins.str]) -> None: + def kid(self, value: builtins.str) -> None: r""" Key identifier (`kid`) embedded in JWT headers. """ diff --git a/ruby/README.md b/ruby/README.md index b81e379..7e9f54a 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -631,7 +631,7 @@ qn.admin.delete_domain_mask(id: "ep-123", domain_mask_id: "dm-1") Configures JWT validation on an endpoint. -**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, optional), `name` (string, optional). +**Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, required), `name` (string, optional). **Returns**: nothing. diff --git a/ruby/sig/quicknode_sdk.rbs b/ruby/sig/quicknode_sdk.rbs index e888823..e188c54 100644 --- a/ruby/sig/quicknode_sdk.rbs +++ b/ruby/sig/quicknode_sdk.rbs @@ -70,7 +70,7 @@ module QuicknodeSdk def delete_ip: (id: String, ip_id: String) -> untyped def create_domain_mask: (id: String, ?domain_mask: String) -> void def delete_domain_mask: (id: String, domain_mask_id: String) -> untyped - def create_jwt: (id: String, ?public_key: String, ?kid: String, ?name: String) -> void + def create_jwt: (id: String, kid: String, ?public_key: String, ?name: String) -> void def delete_jwt: (id: String, jwt_id: String) -> void def create_request_filter: (id: String, ?methods: Array[String]) -> untyped def update_request_filter: (id: String, request_filter_id: String, ?methods: Array[String]) -> void