Skip to content

Commit ff2cdb7

Browse files
committed
Add webhook JWKS API reference
1 parent 7384da6 commit ff2cdb7

3 files changed

Lines changed: 92 additions & 1 deletion

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
title: "Get webhook JWKS"
3+
description: "Fetch Turnkey webhook signature verification keys."
4+
api: "GET https://api.turnkey.com/public/v1/discovery/webhooks/jwks"
5+
authMethod: "none"
6+
playground: "interactive"
7+
---
8+
9+
import { H3Bordered } from "/snippets/h3-bordered.mdx";
10+
import { NestedParam } from "/snippets/nested-param.mdx";
11+
12+
Fetch the public Ed25519 keys used to verify Turnkey webhook signatures. This endpoint requires no authentication.
13+
14+
For full verification guidance, including signed message construction and SDK helper usage, see [Verify webhook signatures](/features/webhooks/verify-signatures).
15+
16+
Cache the JWKS response according to the `Cache-Control` header. Match each JWK `kid` to the webhook delivery's `X-Turnkey-Signature-Key-Id` header, and refetch JWKS before rejecting a delivery with an unknown `kid`.
17+
18+
Current production `Cache-Control`:
19+
20+
```text
21+
public, max-age=86400, s-maxage=86400, stale-if-error=604800
22+
```
23+
24+
<H3Bordered text="Response" />
25+
A successful response returns the following fields:
26+
27+
<ResponseField name="keys" type="array" required={true}>
28+
Public webhook signature verification keys.
29+
<Expandable title="keys details">
30+
<NestedParam parentKey="keys" childKey="kid" type="string" required={true}>
31+
Key identifier. Match this value against the `X-Turnkey-Signature-Key-Id` delivery header.
32+
</NestedParam>
33+
<NestedParam parentKey="keys" childKey="kty" type="string" required={true}>
34+
Key type. The current value is `OKP` for Ed25519 public keys.
35+
</NestedParam>
36+
<NestedParam parentKey="keys" childKey="crv" type="string" required={true}>
37+
Key curve. The current value is `Ed25519`.
38+
</NestedParam>
39+
<NestedParam parentKey="keys" childKey="alg" type="string" required={true}>
40+
JWK algorithm. The current value is `EdDSA`.
41+
</NestedParam>
42+
<NestedParam parentKey="keys" childKey="use" type="string" required={true}>
43+
Key use. The current value is `sig` for signature verification.
44+
</NestedParam>
45+
<NestedParam parentKey="keys" childKey="x" type="string" required={true}>
46+
Base64url-encoded Ed25519 public key.
47+
</NestedParam>
48+
<NestedParam parentKey="keys" childKey="turnkey_signature_algorithm" type="string" required={true}>
49+
Turnkey signature algorithm metadata. The current value is `ed25519`.
50+
</NestedParam>
51+
<NestedParam parentKey="keys" childKey="turnkey_signature_version" type="string" required={true}>
52+
Turnkey signature contract version metadata. The current value is `v1`.
53+
</NestedParam>
54+
</Expandable>
55+
</ResponseField>
56+
57+
<ResponseExample>
58+
59+
```json 200
60+
{
61+
"keys": [
62+
{
63+
"kid": "<signing-key-id>",
64+
"kty": "OKP",
65+
"crv": "Ed25519",
66+
"alg": "EdDSA",
67+
"use": "sig",
68+
"x": "<base64url-encoded-public-key>",
69+
"turnkey_signature_algorithm": "ed25519",
70+
"turnkey_signature_version": "v1"
71+
}
72+
]
73+
}
74+
```
75+
76+
</ResponseExample>

docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@
620620
"api-reference/queries/list-users",
621621
"api-reference/queries/list-wallets",
622622
"api-reference/queries/list-wallets-accounts",
623+
"api-reference/queries/get-webhook-jwks",
623624
"api-reference/queries/list-webhook-endpoints",
624625
"api-reference/queries/validate-container-image-for-tvc",
625626
"api-reference/queries/who-am-i"

scripts/openapi-gen/openapi-gen.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export const tags = ${tagsStr};`;
193193
const uniqueActivityPaths = [...new Set(activityPaths)];
194194
const uniqueQueryPaths = [...new Set(queryPaths)];
195195
const uniqueAuthProxyPaths = [...new Set(authProxyPaths)];
196+
const manualQueryPaths = ["api-reference/queries/get-webhook-jwks"];
196197

197198
// Sort generated paths alphabetically
198199
uniqueActivityPaths.sort();
@@ -253,10 +254,23 @@ export const tags = ${tagsStr};`;
253254
(item: any) => typeof item === "object" && item.group === "Queries"
254255
);
255256
if (queriesGroup) {
256-
queriesGroup.pages = [
257+
const queryPages = [
257258
"api-reference/queries/overview",
258259
...uniqueQueryPaths,
259260
];
261+
for (const manualPath of manualQueryPaths) {
262+
if (queryPages.includes(manualPath)) continue;
263+
264+
const webhookEndpointsIndex = queryPages.indexOf(
265+
"api-reference/queries/list-webhook-endpoints"
266+
);
267+
if (webhookEndpointsIndex === -1) {
268+
queryPages.push(manualPath);
269+
} else {
270+
queryPages.splice(webhookEndpointsIndex, 0, manualPath);
271+
}
272+
}
273+
queriesGroup.pages = queryPages;
260274
console.log(`Updated Queries paths in docs.json`);
261275
} else {
262276
console.warn(

0 commit comments

Comments
 (0)