Skip to content

Commit 6745320

Browse files
vvillait88claude
andcommitted
feat(identity): vendor-namespace UCP signing typ + capability name (1.4.0)
UCP §6 does not define a profile-as-JWS typ, and UCP capability names must follow reverse-DNS namespacing (``^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9_]*)+$``). The previous ``typ: ucp-profile+jws`` and ``agentscore-identity`` capability name implied UCP-canonical signing/slots they aren't. Renamed to vendor-namespaced honest forms: - JWS protected header ``typ``: ``ucp-profile+jws`` -> ``agentscore-profile+jws`` (matches the ``agentscore-risk-signal+jws`` pattern AP2 already uses). - Capability name: ``agentscore-identity`` -> ``sh.agentscore.identity`` (passes the UCP regex; namespace authority ``agentscore.sh``). - Schema URL path: ``agentscore-identity.v1.json`` -> ``sh-agentscore-identity-v1.json`` (path matches the new capability name; URL hosted under namespace authority ``agentscore.sh`` per UCP convention). All 10 cross-lang fixture scenarios re-signed via the new ``scripts/regenerate_cross_lang_fixtures.py`` orchestrator. Hand-crafted ``*-capability.json`` fixtures bumped to the new name to keep the corpus honest about what callers should publish. 871 tests pass at 95.20% coverage. Cross-lang verify against the node sibling's regenerated ``node-*`` corpus passes byte-identically for the data-driven and typed-claims fixtures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7144c52 commit 6745320

28 files changed

Lines changed: 376 additions & 107 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=ke
230230
jwks = build_jwks_response([key.public_jwk])
231231
```
232232

233-
`verify_ucp_profile` enforces the JWS protected header `typ='ucp-profile+jws'`, restricts `alg` to `EdDSA`/`ES256`, requires a `kid`, rejects duplicate kids in the JWKS, and compares the canonical body bytes against the JWS payload to catch swap-after-sign tampering. Failures raise `UCPVerificationError` (a `ValueError` subclass) with a discriminated `code` attribute (`no_signature`/`missing_kid`/`kid_not_found`/`duplicate_kid`/`unsupported_alg`/`wrong_typ`/`signature_invalid`/`body_mismatch`/`malformed_jws`/`malformed_jwks`/`unusable_key`/`unrecognized_critical_header`).
233+
`verify_ucp_profile` enforces the JWS protected header `typ='agentscore-profile+jws'` (vendor-namespaced; UCP §6 does not define a profile-as-JWS typ), restricts `alg` to `EdDSA`/`ES256`, requires a `kid`, rejects duplicate kids in the JWKS, and compares the canonical body bytes against the JWS payload to catch swap-after-sign tampering. Failures raise `UCPVerificationError` (a `ValueError` subclass) with a discriminated `code` attribute (`no_signature`/`missing_kid`/`kid_not_found`/`duplicate_kid`/`unsupported_alg`/`wrong_typ`/`signature_invalid`/`body_mismatch`/`malformed_jws`/`malformed_jwks`/`unusable_key`/`unrecognized_critical_header`).
234234

235235
`sign_ucp_profile` rejects profiles containing `float` values and `int` values whose magnitude exceeds `Number.MAX_SAFE_INTEGER` (2^53 - 1): cross-language float canonicalization is not stable, and Python's arbitrary-width ints lose precision when JS verifiers reparse the canonical body. Use decimal strings (e.g. `"9.99"`) for monetary or fractional fields and for any integer that may exceed the safe range.
236236

agentscore_commerce/identity/ucp.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@
2828

2929
_DEFAULT_VERSION = "2026-04-17"
3030
_SPEC_URL = "https://ucp.dev/"
31-
AGENTSCORE_UCP_CAPABILITY = "agentscore-identity"
31+
# Reverse-DNS namespacing per UCP convention (``^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9_]*)+$``).
32+
# The bare ``agentscore-identity`` form fails the spec regex; vendor-namespacing under the
33+
# ``sh.agentscore`` authority is honest about the capability being our extension, not a
34+
# UCP-canonical slot.
35+
AGENTSCORE_UCP_CAPABILITY = "sh.agentscore.identity"
3236
"""Capability name AgentScore registers in the UCP profile. Consumers filter on this
3337
to find verified-buyer claims attached to the profile."""
3438

@@ -241,7 +245,7 @@ def build_ucp_profile(
241245
"""Compose a UCP profile body for ``/.well-known/ucp`` publication.
242246
243247
Merges AgentScore identity claims into ``capabilities`` as an
244-
``agentscore-identity`` capability when ``data`` carries a resolved operator.
248+
``sh.agentscore.identity`` capability when ``data`` carries a resolved operator.
245249
Consumers reading the profile can opt into the AgentScore claims by filtering
246250
on the capability name.
247251
@@ -325,7 +329,7 @@ async def ucp_profile():
325329
UCPCapability(
326330
name=AGENTSCORE_UCP_CAPABILITY,
327331
version=_AGENTSCORE_CAPABILITY_VERSION,
328-
schema=agentscore_schema_url or "https://agentscore.sh/schemas/ucp/agentscore-identity.v1.json",
332+
schema=agentscore_schema_url or "https://agentscore.sh/schemas/ucp/sh-agentscore-identity-v1.json",
329333
extras={"claims": claims},
330334
),
331335
)

agentscore_commerce/identity/ucp_jwks.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
)
4040

4141
_ALLOWED_ALGS = ("EdDSA", "ES256")
42-
_UCP_TYP = "ucp-profile+jws"
42+
# JWS protected header ``typ`` value. Vendor-namespaced because UCP §6 does not define
43+
# a profile-as-JWS typ; the value advertises that this signed envelope follows the
44+
# AgentScore extension semantics rather than a UCP-canonical signing convention.
45+
_PROFILE_TYP = "agentscore-profile+jws"
4346

4447
_MAX_SAFE_INT = 2**53 - 1
4548

@@ -307,7 +310,7 @@ def sign_ucp_profile(
307310
raise ValueError(msg)
308311

309312
canonical_body = _canonicalize_profile(profile)
310-
header = {"alg": alg, "kid": kid, "typ": _UCP_TYP}
313+
header = {"alg": alg, "kid": kid, "typ": _PROFILE_TYP}
311314
# joserfc treats EdDSA as "not recommended" by default; UCP §6 explicitly accepts
312315
# both EdDSA and ES256, so allow both.
313316
registry = JWSRegistry(algorithms=list(_ALLOWED_ALGS))
@@ -347,7 +350,7 @@ def verify_ucp_profile(
347350
"""Verify a signed UCP profile against a JWKS.
348351
349352
Returns ``True`` when:
350-
* the JWS protected header carries ``kid`` + ``typ='ucp-profile+jws'`` + a
353+
* the JWS protected header carries ``kid`` + ``typ='agentscore-profile+jws'`` + a
351354
registered ``alg`` (EdDSA or ES256),
352355
* the JWKS contains exactly one key with the matching ``kid``,
353356
* the JWS signature validates against that key,
@@ -394,10 +397,10 @@ def verify_ucp_profile(
394397
# Pre-deserialize header checks — joserfc's deserialize_compact accepts kid-less
395398
# JWSs (it iterates the KeySet) so we enforce kid/typ/alg ourselves.
396399
header = _peek_jws_header(sig)
397-
if header.get("typ") != _UCP_TYP:
400+
if header.get("typ") != _PROFILE_TYP:
398401
raise UCPVerificationError(
399402
"wrong_typ",
400-
f"UCP signature typ must be {_UCP_TYP!r}; got {header.get('typ')!r}.",
403+
f"UCP signature typ must be {_PROFILE_TYP!r}; got {header.get('typ')!r}.",
401404
)
402405
if header.get("alg") not in _ALLOWED_ALGS:
403406
raise UCPVerificationError(

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "agentscore-commerce"
7-
version = "1.3.7"
7+
version = "1.4.0"
88
description = "Agent commerce SDK for Python — identity middleware (FastAPI, Flask, Django, AIOHTTP, Sanic, ASGI) + payment helpers + 402 builders + discovery + Stripe multichain. The full merchant-side toolkit for AgentScore-powered agent commerce."
99
readme = "README.md"
1010
license = "MIT"
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
"""Regenerate the full cross-lang fixture corpus (Python side).
2+
3+
Writes all ``py-*.json`` fixtures under ``tests/fixtures/cross-lang/``. Used
4+
after a canonicalization-relevant change (typ rename, capability-name rename,
5+
schema-URL rename, key-sort tweak, etc.) where every JWS in the corpus needs
6+
to be re-signed.
7+
8+
Each scenario hand-crafts the profile body, signs with a fresh keypair, and
9+
writes the ``{profile, jwks, alg, kid, generator}`` envelope. Cross-lang
10+
verify in ``tests/test_ucp_cross_lang.py`` (and the Node sibling) pulls these
11+
in alongside the ``node-*`` fixtures generated by the Node sibling.
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import json
17+
from pathlib import Path
18+
from typing import Any
19+
20+
from agentscore_commerce.identity import (
21+
AssessResult,
22+
OperatorVerification,
23+
UCPCapability,
24+
UCPPaymentHandler,
25+
UCPService,
26+
UCPSigningKey,
27+
build_ucp_profile,
28+
)
29+
from agentscore_commerce.identity.ucp_jwks import (
30+
build_jwks_response,
31+
generate_ucp_signing_key,
32+
sign_ucp_profile,
33+
)
34+
35+
OUT_DIR = Path(__file__).resolve().parent.parent / "tests" / "fixtures" / "cross-lang"
36+
37+
38+
def _write(name: str, env: dict[str, Any]) -> None:
39+
out = OUT_DIR / f"{name}.json"
40+
out.write_text(json.dumps(env, indent=2, ensure_ascii=False) + "\n")
41+
print(f"wrote {out}")
42+
43+
44+
def _envelope(signed: dict[str, Any], public_jwk: dict[str, Any], alg: str, kid: str) -> dict[str, Any]:
45+
return {
46+
"profile": signed,
47+
"jwks": build_jwks_response([public_jwk]),
48+
"alg": alg,
49+
"kid": kid,
50+
"generator": "python",
51+
}
52+
53+
54+
def main() -> None:
55+
# py-minimal
56+
kid = "py-minimal-EdDSA"
57+
key = generate_ucp_signing_key(kid=kid)
58+
profile = build_ucp_profile(
59+
name="Minimal Merchant",
60+
services=[UCPService(type="rest", url="https://m.example.com")],
61+
payment_handlers=[],
62+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
63+
)
64+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
65+
_write("py-minimal", _envelope(signed, key.public_jwk, "EdDSA", kid))
66+
67+
# py-es256-rails
68+
kid = "py-es256-rails-ES256"
69+
key = generate_ucp_signing_key(kid=kid, alg="ES256")
70+
profile = build_ucp_profile(
71+
name="ES256 Merchant",
72+
services=[
73+
UCPService(type="rest", url="https://a.example.com"),
74+
UCPService(type="a2a", url="https://a.example.com/agent-card.json"),
75+
],
76+
payment_handlers=[
77+
UCPPaymentHandler(name="tempo", config={"rail": "tempo-mainnet", "chain_id": 4217}),
78+
UCPPaymentHandler(name="x402", config={"networks": ["base-8453"]}),
79+
],
80+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
81+
)
82+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid, alg="ES256")
83+
_write("py-es256-rails", _envelope(signed, key.public_jwk, "ES256", kid))
84+
85+
# py-extras-int
86+
kid = "py-extras-int-EdDSA"
87+
key = generate_ucp_signing_key(kid=kid)
88+
profile = build_ucp_profile(
89+
name="Extras Merchant",
90+
services=[UCPService(type="rest", url="https://e.example.com")],
91+
payment_handlers=[UCPPaymentHandler(name="stripe", config={"profile_id": "abc", "count": 7})],
92+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
93+
)
94+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
95+
_write("py-extras-int", _envelope(signed, key.public_jwk, "EdDSA", kid))
96+
97+
# py-capability — hand-crafted vendor capability (renamed to
98+
# sh.agentscore.identity to match the new namespace; the in-fixture name
99+
# is independent of the SDK's auto-injection but consistency keeps the
100+
# corpus honest about what callers should publish).
101+
kid = "py-capability-EdDSA"
102+
key = generate_ucp_signing_key(kid=kid)
103+
profile = build_ucp_profile(
104+
name="Capability Merchant",
105+
services=[UCPService(type="rest", url="https://c.example.com")],
106+
capabilities=[
107+
UCPCapability(
108+
name="sh.agentscore.identity",
109+
schema="https://agentscore.sh/schema/identity/1",
110+
version="1",
111+
extras={"kyc_required": True},
112+
),
113+
],
114+
payment_handlers=[
115+
UCPPaymentHandler(name="tempo", config={"rail": "tempo-mainnet", "chain_id": 4217}),
116+
],
117+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
118+
)
119+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
120+
_write("py-capability", _envelope(signed, key.public_jwk, "EdDSA", kid))
121+
122+
# py-unicode
123+
kid = "py-unicode-EdDSA"
124+
key = generate_ucp_signing_key(kid=kid)
125+
profile = build_ucp_profile(
126+
name="Café 日本 🍷 Merchant",
127+
services=[UCPService(type="rest", url="https://日本.example.com")],
128+
payment_handlers=[UCPPaymentHandler(name="tempo", config={"note": "メモ"})],
129+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
130+
)
131+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
132+
_write("py-unicode", _envelope(signed, key.public_jwk, "EdDSA", kid))
133+
134+
# py-multikey — JWKS with two keys, signed by the newer one.
135+
old_key = generate_ucp_signing_key(kid="py-multikey-old")
136+
new_key = generate_ucp_signing_key(kid="py-multikey-new")
137+
profile = build_ucp_profile(
138+
name="Multi-Key Merchant",
139+
services=[UCPService(type="rest", url="https://mk.example.com")],
140+
payment_handlers=[UCPPaymentHandler(name="tempo", config={"rail": "tempo-mainnet"})],
141+
signing_keys=[
142+
UCPSigningKey.from_jwk(old_key.public_jwk),
143+
UCPSigningKey.from_jwk(new_key.public_jwk),
144+
],
145+
)
146+
signed = sign_ucp_profile(profile.to_dict(), signing_key=new_key.private_key, kid="py-multikey-new")
147+
_write(
148+
"py-multikey",
149+
{
150+
"profile": signed,
151+
"jwks": build_jwks_response([old_key.public_jwk, new_key.public_jwk]),
152+
"alg": "EdDSA",
153+
"kid": "py-multikey-new",
154+
"generator": "python",
155+
},
156+
)
157+
158+
# py-emoji-keys — extras with non-ASCII object keys (BMP private use, CJK
159+
# compatibility, supplementary plane). Exercises codepoint-vs-UTF-16 sort.
160+
kid = "py-emoji-keys-EdDSA"
161+
key = generate_ucp_signing_key(kid=kid)
162+
profile = build_ucp_profile(
163+
name="Emoji Keys Merchant",
164+
services=[UCPService(type="rest", url="https://emoji.example.com")],
165+
payment_handlers=[UCPPaymentHandler(name="tempo", config={})],
166+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
167+
extras={
168+
"extras": {
169+
"a": 1,
170+
"豈": 2,
171+
"": 3,
172+
"🍷": 4,
173+
},
174+
},
175+
)
176+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
177+
_write("py-emoji-keys", _envelope(signed, key.public_jwk, "EdDSA", kid))
178+
179+
# py-int-boundary — exercises Number.MAX_SAFE_INTEGER round-trip.
180+
kid = "py-int-boundary-EdDSA"
181+
key = generate_ucp_signing_key(kid=kid)
182+
profile = build_ucp_profile(
183+
name="Int Boundary Merchant",
184+
services=[UCPService(type="rest", url="https://i.example.com")],
185+
payment_handlers=[],
186+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
187+
extras={
188+
"extras": {
189+
"max_safe_int": 9007199254740991,
190+
"min_safe_int": -9007199254740991,
191+
"small_int": 42,
192+
"neg_small_int": -42,
193+
"zero": 0,
194+
},
195+
},
196+
)
197+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
198+
_write("py-int-boundary", _envelope(signed, key.public_jwk, "EdDSA", kid))
199+
200+
# py-data-driven-claims — exercises the build_ucp_profile data path with
201+
# API-shape "missing" sentinels (empty string + None). Both languages MUST
202+
# emit identical canonical bytes for this input.
203+
kid = "py-data-driven-claims-EdDSA"
204+
key = generate_ucp_signing_key(kid=kid)
205+
result = AssessResult(
206+
allow=True,
207+
resolved_operator="op_data_driven",
208+
verify_url="https://agentscore.sh/verify/op_data_driven",
209+
raw={
210+
"account_verification": {
211+
"kyc_level": "",
212+
"sanctions_clear": False,
213+
"age_bracket": None,
214+
"jurisdiction": None,
215+
"verified_at": None,
216+
},
217+
},
218+
)
219+
profile = build_ucp_profile(
220+
name="Data Driven Claims Merchant",
221+
services=[UCPService(type="rest", url="https://d.example.com")],
222+
payment_handlers=[],
223+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
224+
data=result,
225+
)
226+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
227+
_write("py-data-driven-claims", _envelope(signed, key.public_jwk, "EdDSA", kid))
228+
229+
# py-typed-claims — exercises the typed AssessResult fields (no raw
230+
# fallback). Cross-lang parity check for the typed-field-only call site.
231+
kid = "py-typed-claims-EdDSA"
232+
key = generate_ucp_signing_key(kid=kid)
233+
result = AssessResult(
234+
allow=True,
235+
resolved_operator="op_typed_claims",
236+
verify_url="https://agentscore.sh/verify/op_typed_claims",
237+
operator_verification=OperatorVerification(
238+
level="enhanced",
239+
operator_type="api",
240+
verified_at="2026-04-01T00:00:00Z",
241+
),
242+
account_verification={
243+
"kyc_level": "enhanced",
244+
"sanctions_clear": True,
245+
"age_bracket": "21+",
246+
"jurisdiction": "US",
247+
"verified_at": "2026-04-01T00:00:00Z",
248+
},
249+
raw=None,
250+
)
251+
profile = build_ucp_profile(
252+
name="Typed Claims Merchant",
253+
services=[UCPService(type="rest", url="https://t.example.com")],
254+
payment_handlers=[],
255+
signing_keys=[UCPSigningKey.from_jwk(key.public_jwk)],
256+
data=result,
257+
)
258+
signed = sign_ucp_profile(profile.to_dict(), signing_key=key.private_key, kid=kid)
259+
_write("py-typed-claims", _envelope(signed, key.public_jwk, "EdDSA", kid))
260+
261+
262+
if __name__ == "__main__":
263+
main()

tests/fixtures/cross-lang/node-capability.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
],
1111
"capabilities": [
1212
{
13-
"name": "agentscore-identity",
13+
"name": "sh.agentscore.identity",
1414
"schema": "https://agentscore.sh/schema/identity/1",
1515
"version": "1",
1616
"kyc_required": true
@@ -32,11 +32,11 @@
3232
"use": "sig",
3333
"crv": "Ed25519",
3434
"kty": "OKP",
35-
"x": "8zz-L1N_SZ0EUmciU1IzuxBuGd67MSg-OemKm6ofmgg"
35+
"x": "kFgwv82ZN7H3jk9gHbUDTi6EZZeaUUBsLBgnfm8Mtog"
3636
}
3737
],
3838
"name": "Capability Merchant",
39-
"signature": "eyJhbGciOiJFZERTQSIsImtpZCI6Im5vZGUtY2FwYWJpbGl0eS1FZERTQSIsInR5cCI6InVjcC1wcm9maWxlK2p3cyJ9.eyJjYXBhYmlsaXRpZXMiOlt7Imt5Y19yZXF1aXJlZCI6dHJ1ZSwibmFtZSI6ImFnZW50c2NvcmUtaWRlbnRpdHkiLCJzY2hlbWEiOiJodHRwczovL2FnZW50c2NvcmUuc2gvc2NoZW1hL2lkZW50aXR5LzEiLCJ2ZXJzaW9uIjoiMSJ9XSwibmFtZSI6IkNhcGFiaWxpdHkgTWVyY2hhbnQiLCJwYXltZW50X2hhbmRsZXJzIjpbeyJjb25maWciOnsiY2hhaW5faWQiOjQyMTcsInJhaWwiOiJ0ZW1wby1tYWlubmV0In0sIm5hbWUiOiJ0ZW1wbyJ9XSwic2VydmljZXMiOlt7InR5cGUiOiJyZXN0IiwidXJsIjoiaHR0cHM6Ly9jLmV4YW1wbGUuY29tIn1dLCJzaWduaW5nX2tleXMiOlt7ImFsZyI6IkVkRFNBIiwiY3J2IjoiRWQyNTUxOSIsImtpZCI6Im5vZGUtY2FwYWJpbGl0eS1FZERTQSIsImt0eSI6Ik9LUCIsInVzZSI6InNpZyIsIngiOiI4enotTDFOX1NaMEVVbWNpVTFJenV4QnVHZDY3TVNnLU9lbUttNm9mbWdnIn1dLCJzcGVjIjoiaHR0cHM6Ly91Y3AuZGV2LyIsInZlcnNpb24iOiIyMDI2LTA0LTE3In0.YmiTy87alEbVfAEXYzXYkBrsbO_kHqgTSlv3gKuzy6Oere-pJl0PmZ8zGW2uTyjaGC9OFbjLUIzowY3jnJmGAg"
39+
"signature": "eyJhbGciOiJFZERTQSIsImtpZCI6Im5vZGUtY2FwYWJpbGl0eS1FZERTQSIsInR5cCI6ImFnZW50c2NvcmUtcHJvZmlsZStqd3MifQ.eyJjYXBhYmlsaXRpZXMiOlt7Imt5Y19yZXF1aXJlZCI6dHJ1ZSwibmFtZSI6InNoLmFnZW50c2NvcmUuaWRlbnRpdHkiLCJzY2hlbWEiOiJodHRwczovL2FnZW50c2NvcmUuc2gvc2NoZW1hL2lkZW50aXR5LzEiLCJ2ZXJzaW9uIjoiMSJ9XSwibmFtZSI6IkNhcGFiaWxpdHkgTWVyY2hhbnQiLCJwYXltZW50X2hhbmRsZXJzIjpbeyJjb25maWciOnsiY2hhaW5faWQiOjQyMTcsInJhaWwiOiJ0ZW1wby1tYWlubmV0In0sIm5hbWUiOiJ0ZW1wbyJ9XSwic2VydmljZXMiOlt7InR5cGUiOiJyZXN0IiwidXJsIjoiaHR0cHM6Ly9jLmV4YW1wbGUuY29tIn1dLCJzaWduaW5nX2tleXMiOlt7ImFsZyI6IkVkRFNBIiwiY3J2IjoiRWQyNTUxOSIsImtpZCI6Im5vZGUtY2FwYWJpbGl0eS1FZERTQSIsImt0eSI6Ik9LUCIsInVzZSI6InNpZyIsIngiOiJrRmd3djgyWk43SDNqazlnSGJVRFRpNkVaWmVhVVVCc0xCZ25mbThNdG9nIn1dLCJzcGVjIjoiaHR0cHM6Ly91Y3AuZGV2LyIsInZlcnNpb24iOiIyMDI2LTA0LTE3In0.PIG6fQt84ZM1r08g7_vsl1Hhi6B385BFnPCKo7WkbsyjcpKFpvidTmwBjZ6auUzEOyag6IF0OmEz_8gotuEZAw"
4040
},
4141
"jwks": {
4242
"keys": [
@@ -46,7 +46,7 @@
4646
"use": "sig",
4747
"crv": "Ed25519",
4848
"kty": "OKP",
49-
"x": "8zz-L1N_SZ0EUmciU1IzuxBuGd67MSg-OemKm6ofmgg"
49+
"x": "kFgwv82ZN7H3jk9gHbUDTi6EZZeaUUBsLBgnfm8Mtog"
5050
}
5151
]
5252
},

0 commit comments

Comments
 (0)