@necessarysdk/react-native 0.0.0-stage → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +2 -0
  4. package/NecessaryReactNative.podspec +23 -0
  5. package/README.md +429 -2
  6. package/android/build.gradle +83 -0
  7. package/android/src/main/AndroidManifest.xml +41 -0
  8. package/android/src/main/cpp/CMakeLists.txt +7 -0
  9. package/android/src/main/cpp/code_integrity.cpp +484 -0
  10. package/android/src/main/java/com/necessarysdk/reactnative/Causes.kt +49 -0
  11. package/android/src/main/java/com/necessarysdk/reactnative/InstallationKeyManager.kt +388 -0
  12. package/android/src/main/java/com/necessarysdk/reactnative/IntegrityProbeManager.kt +1157 -0
  13. package/android/src/main/java/com/necessarysdk/reactnative/KeyPresence.kt +62 -0
  14. package/android/src/main/java/com/necessarysdk/reactnative/NecessaryModules.kt +94 -0
  15. package/android/src/main/java/com/necessarysdk/reactnative/NecessaryNative.kt +338 -0
  16. package/android/src/main/java/com/necessarysdk/reactnative/NecessaryPackage.kt +38 -0
  17. package/android/src/main/java/com/necessarysdk/reactnative/ProbeReads.kt +333 -0
  18. package/android/src/main/java/com/necessarysdk/reactnative/ScreenGuard.kt +56 -0
  19. package/android/src/main/java/com/necessarysdk/reactnative/SecureStore.kt +127 -0
  20. package/android/src/main/java/com/necessarysdk/reactnative/StepUpKeyEntry.kt +57 -0
  21. package/android/src/main/java/com/necessarysdk/reactnative/StepUpKeyManager.kt +767 -0
  22. package/contract/report-1/android-8-ios-5/RULES.md +149 -0
  23. package/contract/report-1/android-8-ios-5/report.schema.json +2753 -0
  24. package/contract/report-1/android-8-ios-5/samples/android-8-complete.json +205 -0
  25. package/contract/report-1/android-8-ios-5/samples/android-8-incomplete.json +205 -0
  26. package/contract/report-1/android-8-ios-5/samples/android-8-invalid.json +205 -0
  27. package/contract/report-1/android-8-ios-5/samples/android-8-location-one-fix.json +228 -0
  28. package/contract/report-1/android-8-ios-5/samples/android-8-location-two-fixes.json +228 -0
  29. package/contract/report-1/android-8-ios-5/samples/android-8-refused.json +208 -0
  30. package/contract/report-1/android-8-ios-5/samples/ios-5-complete.json +106 -0
  31. package/contract/report-1/android-8-ios-5/samples/ios-5-incomplete.json +105 -0
  32. package/contract/report-1/android-8-ios-5/samples/ios-5-invalid.json +107 -0
  33. package/contract/report-1/android-8-ios-5/samples/ios-5-partial.json +110 -0
  34. package/contract/report-1/android-8-ios-5/samples/ios-5-refused.json +109 -0
  35. package/doc/integration_guide.md +771 -0
  36. package/doc/measurements.md +774 -0
  37. package/ios/InstallationKeyManager.swift +694 -0
  38. package/ios/IntegrityProbeManager.swift +959 -0
  39. package/ios/NecessaryModules.h +34 -0
  40. package/ios/NecessaryModules.mm +208 -0
  41. package/ios/NecessaryNative.swift +327 -0
  42. package/ios/PrivacyInfo.xcprivacy +14 -0
  43. package/ios/ProbeReads.swift +370 -0
  44. package/lib/client.d.ts +105 -0
  45. package/lib/client.js +176 -0
  46. package/lib/collector.d.ts +18 -0
  47. package/lib/collector.js +49 -0
  48. package/lib/deviceTrust.d.ts +253 -0
  49. package/lib/deviceTrust.js +699 -0
  50. package/lib/errors.d.ts +43 -0
  51. package/lib/errors.js +56 -0
  52. package/lib/index.d.ts +18 -0
  53. package/lib/index.js +34 -0
  54. package/lib/installationKey.d.ts +62 -0
  55. package/lib/installationKey.js +185 -0
  56. package/lib/installationStore.d.ts +49 -0
  57. package/lib/installationStore.js +127 -0
  58. package/lib/native/NativeNecessaryInstallationKey.d.ts +10 -0
  59. package/lib/native/NativeNecessaryInstallationKey.js +4 -0
  60. package/lib/native/NativeNecessaryIntegrity.d.ts +8 -0
  61. package/lib/native/NativeNecessaryIntegrity.js +4 -0
  62. package/lib/native/NativeNecessarySecureScreen.d.ts +7 -0
  63. package/lib/native/NativeNecessarySecureScreen.js +4 -0
  64. package/lib/native/NativeNecessaryStepUpKey.d.ts +9 -0
  65. package/lib/native/NativeNecessaryStepUpKey.js +4 -0
  66. package/lib/native/NativeNecessaryStorage.d.ts +14 -0
  67. package/lib/native/NativeNecessaryStorage.js +4 -0
  68. package/lib/protocol.d.ts +24 -0
  69. package/lib/protocol.js +50 -0
  70. package/lib/reinstallHint.d.ts +23 -0
  71. package/lib/reinstallHint.js +65 -0
  72. package/lib/report.d.ts +62 -0
  73. package/lib/report.js +134 -0
  74. package/lib/requestProof.d.ts +116 -0
  75. package/lib/requestProof.js +220 -0
  76. package/lib/secureScreen.d.ts +15 -0
  77. package/lib/secureScreen.js +32 -0
  78. package/lib/stepUpKey.d.ts +105 -0
  79. package/lib/stepUpKey.js +187 -0
  80. package/lib/transport.d.ts +39 -0
  81. package/lib/transport.js +117 -0
  82. package/lib/util/answers.d.ts +6 -0
  83. package/lib/util/answers.js +16 -0
  84. package/lib/util/bytes.d.ts +18 -0
  85. package/lib/util/bytes.js +207 -0
  86. package/lib/util/native.d.ts +20 -0
  87. package/lib/util/native.js +49 -0
  88. package/lib/util/release.d.ts +2 -0
  89. package/lib/util/release.js +7 -0
  90. package/lib/util/target.d.ts +18 -0
  91. package/lib/util/target.js +128 -0
  92. package/package.json +81 -4
  93. package/src/client.ts +221 -0
  94. package/src/collector.ts +64 -0
  95. package/src/deviceTrust.ts +851 -0
  96. package/src/errors.ts +71 -0
  97. package/src/index.ts +19 -0
  98. package/src/installationKey.ts +223 -0
  99. package/src/installationStore.ts +143 -0
  100. package/src/native/NativeNecessaryInstallationKey.ts +12 -0
  101. package/src/native/NativeNecessaryIntegrity.ts +15 -0
  102. package/src/native/NativeNecessarySecureScreen.ts +9 -0
  103. package/src/native/NativeNecessaryStepUpKey.ts +11 -0
  104. package/src/native/NativeNecessaryStorage.ts +16 -0
  105. package/src/protocol.ts +52 -0
  106. package/src/reinstallHint.ts +69 -0
  107. package/src/report.ts +168 -0
  108. package/src/requestProof.ts +295 -0
  109. package/src/secureScreen.ts +29 -0
  110. package/src/stepUpKey.ts +238 -0
  111. package/src/transport.ts +145 -0
  112. package/src/util/answers.ts +15 -0
  113. package/src/util/bytes.ts +194 -0
  114. package/src/util/native.ts +56 -0
  115. package/src/util/release.ts +6 -0
  116. package/src/util/target.ts +132 -0
  117. package/vectors/client_server.json +264 -0
@@ -0,0 +1,132 @@
1
+ /**
2
+ * A request's target as a proof names it: its path and its query, normalized exactly as the
3
+ * request is sent -- an escape of an unreserved character decoded, every other escape in upper
4
+ * case, a character a path or a query may not hold escaped as UTF-8, and dot segments removed.
5
+ * The transport sends the same normalized target, so what is signed is what is sent.
6
+ */
7
+
8
+ const UNRESERVED = /[A-Za-z0-9\-._~]/;
9
+ const SUB_DELIMS = "!$&'()*+,;=";
10
+ const PATH_EXTRA = ':@/';
11
+ const QUERY_EXTRA = ':@/?';
12
+
13
+ function allowed(char: string, extra: string): boolean {
14
+ return UNRESERVED.test(char) || SUB_DELIMS.includes(char) || extra.includes(char);
15
+ }
16
+
17
+ function isHex(code: number): boolean {
18
+ return (code >= 48 && code <= 57) || (code >= 65 && code <= 70) || (code >= 97 && code <= 102);
19
+ }
20
+
21
+ function escapeByte(byte: number): string {
22
+ return '%' + (byte < 16 ? '0' : '') + byte.toString(16).toUpperCase();
23
+ }
24
+
25
+ function escapeCodePoint(code: number): string {
26
+ const bytes: number[] = [];
27
+ if (code < 0x80) {
28
+ bytes.push(code);
29
+ } else if (code < 0x800) {
30
+ bytes.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
31
+ } else if (code < 0x10000) {
32
+ bytes.push(0xe0 | (code >> 12), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f));
33
+ } else {
34
+ bytes.push(0xf0 | (code >> 18), 0x80 | ((code >> 12) & 0x3f), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f));
35
+ }
36
+ return bytes.map(escapeByte).join('');
37
+ }
38
+
39
+ function normalize(component: string, extra: string): string {
40
+ let out = '';
41
+ for (let i = 0; i < component.length; i++) {
42
+ const char = component[i];
43
+ const code = component.charCodeAt(i);
44
+ if (code < 128 && allowed(char, extra)) {
45
+ out += char;
46
+ } else if (char === '%') {
47
+ const valid = i + 2 < component.length &&
48
+ isHex(component.charCodeAt(i + 1)) && isHex(component.charCodeAt(i + 2));
49
+ if (!valid) {
50
+ out += '%25';
51
+ continue;
52
+ }
53
+ const value = parseInt(component.substr(i + 1, 2), 16);
54
+ const decoded = String.fromCharCode(value);
55
+ if (UNRESERVED.test(decoded)) {
56
+ out += decoded;
57
+ } else {
58
+ out += component.substr(i, 3).toUpperCase();
59
+ }
60
+ i += 2;
61
+ } else if (code >= 0xd800 && code <= 0xdbff && i + 1 < component.length &&
62
+ component.charCodeAt(i + 1) >= 0xdc00 && component.charCodeAt(i + 1) <= 0xdfff) {
63
+ out += escapeCodePoint(0x10000 + ((code - 0xd800) << 10) + (component.charCodeAt(i + 1) - 0xdc00));
64
+ i++;
65
+ } else if (code >= 0xd800 && code <= 0xdfff) {
66
+ out += escapeCodePoint(0xfffd);
67
+ } else {
68
+ out += escapeCodePoint(code);
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+
74
+ function removeDotSegments(path: string): string {
75
+ if (!(path.startsWith('.') || path.includes('/.'))) {
76
+ return path;
77
+ }
78
+ const output: string[] = [];
79
+ let appendSlash = false;
80
+ for (const segment of path.split('/')) {
81
+ appendSlash = false;
82
+ if (segment === '..') {
83
+ if (output.length > 0) {
84
+ output.pop();
85
+ if (output.length === 0) {
86
+ output.push('');
87
+ }
88
+ }
89
+ appendSlash = true;
90
+ } else if (segment === '.') {
91
+ appendSlash = true;
92
+ } else {
93
+ output.push(segment);
94
+ }
95
+ }
96
+ if (appendSlash) {
97
+ output.push('');
98
+ }
99
+ return output.join('/');
100
+ }
101
+
102
+ export interface Target {
103
+ /** The path, without the query. */
104
+ path: string;
105
+ /** The query as sent, without its `?`; empty when there is none. */
106
+ query: string;
107
+ /** Whether the target has a `?` at all. */
108
+ hasQuery: boolean;
109
+ }
110
+
111
+ /** [target] -- a path with its query, such as `/v1/items?limit=5` -- as a proof names it. */
112
+ export function parseTarget(target: string): Target {
113
+ let rest = target;
114
+ const hash = rest.indexOf('#');
115
+ if (hash >= 0) {
116
+ rest = rest.substring(0, hash);
117
+ }
118
+ const mark = rest.indexOf('?');
119
+ const rawPath = mark >= 0 ? rest.substring(0, mark) : rest;
120
+ const rawQuery = mark >= 0 ? rest.substring(mark + 1) : '';
121
+ return {
122
+ path: removeDotSegments(normalize(rawPath, PATH_EXTRA)),
123
+ query: normalize(rawQuery, QUERY_EXTRA),
124
+ hasQuery: mark >= 0,
125
+ };
126
+ }
127
+
128
+ /** [target] as the transport sends it: the same normalized path and query. */
129
+ export function normalizedTarget(target: string): string {
130
+ const parsed = parseTarget(target);
131
+ return parsed.hasQuery ? `${parsed.path}?${parsed.query}` : parsed.path;
132
+ }
@@ -0,0 +1,264 @@
1
+ {
2
+ "about": "Shared vectors: what a client must produce, byte for byte, and what a backend must accept -- the integration guide's sections 1 to 3 (doc/integration_guide.md). test/clientServerVectors.test.ts holds the SDK to them; a backend can test itself against them too.",
3
+ "access_proof": [
4
+ {
5
+ "name": "a GET without a query",
6
+ "method": "GET",
7
+ "path": "/v1/account/me",
8
+ "body": null,
9
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
10
+ "installation_id": "11111111-2222-4333-8444-555555555555",
11
+ "nonce": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
12
+ "timestamp": 1760000000,
13
+ "sent_body": "",
14
+ "proof_json": "{\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"body_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"method\":\"GET\",\"nonce\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"path\":\"/v1/account/me\",\"query\":\"\",\"timestamp\":1760000000,\"version\":2}",
15
+ "proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiZTNiMGM0NDI5OGZjMWMxNDlhZmJmNGM4OTk2ZmI5MjQyN2FlNDFlNDY0OWI5MzRjYTQ5NTk5MWI3ODUyYjg1NSIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IkdFVCIsIm5vbmNlIjoiQUFFQ0F3UUZCZ2NJQ1FvTERBME9EeEFSRWhNVUZSWVhHQmthR3h3ZEhoOCIsInBhdGgiOiIvdjEvYWNjb3VudC9tZSIsInF1ZXJ5IjoiIiwidGltZXN0YW1wIjoxNzYwMDAwMDAwLCJ2ZXJzaW9uIjoyfQ"
16
+ },
17
+ {
18
+ "name": "a GET with a query",
19
+ "method": "GET",
20
+ "path": "/v1/auth/approvals?limit=5&state=pending",
21
+ "body": null,
22
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
23
+ "installation_id": "11111111-2222-4333-8444-555555555555",
24
+ "nonce": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
25
+ "timestamp": 1760000001,
26
+ "sent_body": "",
27
+ "proof_json": "{\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"body_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"method\":\"GET\",\"nonce\":\"ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8\",\"path\":\"/v1/auth/approvals\",\"query\":\"limit=5&state=pending\",\"timestamp\":1760000001,\"version\":2}",
28
+ "proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiZTNiMGM0NDI5OGZjMWMxNDlhZmJmNGM4OTk2ZmI5MjQyN2FlNDFlNDY0OWI5MzRjYTQ5NTk5MWI3ODUyYjg1NSIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IkdFVCIsIm5vbmNlIjoiSUNFaUl5UWxKaWNvS1NvckxDMHVMekF4TWpNME5UWTNPRGs2T3p3OVBqOCIsInBhdGgiOiIvdjEvYXV0aC9hcHByb3ZhbHMiLCJxdWVyeSI6ImxpbWl0PTUmc3RhdGU9cGVuZGluZyIsInRpbWVzdGFtcCI6MTc2MDAwMDAwMSwidmVyc2lvbiI6Mn0"
29
+ },
30
+ {
31
+ "name": "a POST whose body has text beyond ASCII, a slash and a quote",
32
+ "method": "POST",
33
+ "path": "/v1/account/transfer",
34
+ "body": {
35
+ "amount": 5,
36
+ "note": "café / €",
37
+ "quote": "\"x\""
38
+ },
39
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
40
+ "installation_id": "11111111-2222-4333-8444-555555555555",
41
+ "nonce": "QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl8",
42
+ "timestamp": 1760000002,
43
+ "sent_body": "{\"amount\":5,\"note\":\"café / €\",\"quote\":\"\\\"x\\\"\"}",
44
+ "proof_json": "{\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"body_sha256\":\"f5d6a1ba97ae61dda0a2fe5cddc9861f31ed49f04806c30cc1bfc122856c966b\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"method\":\"POST\",\"nonce\":\"QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl8\",\"path\":\"/v1/account/transfer\",\"query\":\"\",\"timestamp\":1760000002,\"version\":2}",
45
+ "proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiZjVkNmExYmE5N2FlNjFkZGEwYTJmZTVjZGRjOTg2MWYzMWVkNDlmMDQ4MDZjMzBjYzFiZmMxMjI4NTZjOTY2YiIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6IlFFRkNRMFJGUmtkSVNVcExURTFPVDFCUlVsTlVWVlpYV0ZsYVcxeGRYbDgiLCJwYXRoIjoiL3YxL2FjY291bnQvdHJhbnNmZXIiLCJxdWVyeSI6IiIsInRpbWVzdGFtcCI6MTc2MDAwMDAwMiwidmVyc2lvbiI6Mn0"
46
+ },
47
+ {
48
+ "name": "a POST with a query and an empty body",
49
+ "method": "POST",
50
+ "path": "/v1/business/runtime-baselines/0d4f6c1a-3b2e-4f5a-9c8d-7e6f5a4b3c2d/retire?dry_run=1",
51
+ "body": {},
52
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
53
+ "installation_id": "11111111-2222-4333-8444-555555555555",
54
+ "nonce": "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8",
55
+ "timestamp": 1760000003,
56
+ "sent_body": "{}",
57
+ "proof_json": "{\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"body_sha256\":\"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"method\":\"POST\",\"nonce\":\"YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8\",\"path\":\"/v1/business/runtime-baselines/0d4f6c1a-3b2e-4f5a-9c8d-7e6f5a4b3c2d/retire\",\"query\":\"dry_run=1\",\"timestamp\":1760000003,\"version\":2}",
58
+ "proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiNDQxMzZmYTM1NWIzNjc4YTExNDZhZDE2ZjdlODY0OWU5NGZiNGZjMjFmZTc3ZTgzMTBjMDYwZjYxY2FhZmY4YSIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6IllHRmlZMlJsWm1kb2FXcHJiRzF1YjNCeGNuTjBkWFozZUhsNmUzeDlmbjgiLCJwYXRoIjoiL3YxL2J1c2luZXNzL3J1bnRpbWUtYmFzZWxpbmVzLzBkNGY2YzFhLTNiMmUtNGY1YS05YzhkLTdlNmY1YTRiM2MyZC9yZXRpcmUiLCJxdWVyeSI6ImRyeV9ydW49MSIsInRpbWVzdGFtcCI6MTc2MDAwMDAwMywidmVyc2lvbiI6Mn0"
59
+ },
60
+ {
61
+ "name": "a GET whose query is percent-encoded",
62
+ "method": "GET",
63
+ "path": "/v1/business/graph?handle=a%20b%2Bc",
64
+ "body": null,
65
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
66
+ "installation_id": "11111111-2222-4333-8444-555555555555",
67
+ "nonce": "gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp8",
68
+ "timestamp": 1760000004,
69
+ "sent_body": "",
70
+ "proof_json": "{\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"body_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"method\":\"GET\",\"nonce\":\"gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp8\",\"path\":\"/v1/business/graph\",\"query\":\"handle=a%20b%2Bc\",\"timestamp\":1760000004,\"version\":2}",
71
+ "proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiZTNiMGM0NDI5OGZjMWMxNDlhZmJmNGM4OTk2ZmI5MjQyN2FlNDFlNDY0OWI5MzRjYTQ5NTk5MWI3ODUyYjg1NSIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IkdFVCIsIm5vbmNlIjoiZ0lHQ2c0U0Zob2VJaVlxTGpJMk9qNUNSa3BPVWxaYVhtSm1hbTV5ZG5wOCIsInBhdGgiOiIvdjEvYnVzaW5lc3MvZ3JhcGgiLCJxdWVyeSI6ImhhbmRsZT1hJTIwYiUyQmMiLCJ0aW1lc3RhbXAiOjE3NjAwMDAwMDQsInZlcnNpb24iOjJ9"
72
+ }
73
+ ],
74
+ "operation": [
75
+ {
76
+ "name": "a transfer",
77
+ "method": "post",
78
+ "path": "/v1/account/transfer",
79
+ "body": {
80
+ "amount": 2500,
81
+ "to": "payee-7",
82
+ "note": "rent – märz"
83
+ },
84
+ "sent_body": "{\"amount\":2500,\"to\":\"payee-7\",\"note\":\"rent – märz\"}",
85
+ "operation": {
86
+ "method": "POST",
87
+ "path": "/v1/account/transfer",
88
+ "query": "",
89
+ "body_sha256": "98ab62dc38b20668da3e00e2f084116da5abc0d7b7a6e1cd4b0a682328990ef5"
90
+ }
91
+ },
92
+ {
93
+ "name": "an empty body",
94
+ "method": "POST",
95
+ "path": "/v1/account/sensitive-echo",
96
+ "body": {},
97
+ "sent_body": "{}",
98
+ "operation": {
99
+ "method": "POST",
100
+ "path": "/v1/account/sensitive-echo",
101
+ "query": "",
102
+ "body_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
103
+ }
104
+ }
105
+ ],
106
+ "thumbprint": [
107
+ {
108
+ "name": "a P-256 key",
109
+ "jwk": {
110
+ "kty": "EC",
111
+ "crv": "P-256",
112
+ "alg": "ES256",
113
+ "x": "gj4omMloswXs_xmCpuJRSfT_zhni0FN7RAUphteOih4",
114
+ "y": "yi8X_0pisZv5qnqdeY_wuTEayYgtLQHC0PdeqlCPafo"
115
+ },
116
+ "thumbprint": "f312c43658756ed4ae5af0d111e5ed83b643f6c4fbb5dcc28f48aecafd0294e0"
117
+ },
118
+ {
119
+ "name": "another P-256 key",
120
+ "jwk": {
121
+ "kty": "EC",
122
+ "crv": "P-256",
123
+ "alg": "ES256",
124
+ "x": "3AecBt0C5KPzTZLp95heI8Nr9Xmkirqarom0i4qA2XA",
125
+ "y": "TZxl4m9FWOeEc6qsaPscfUD6S7NzvO1siUIZXPWTWps"
126
+ },
127
+ "thumbprint": "261f0cdeeb8d013f0bd212205f97a521a744eac8743eee04d1fe73105ed36118"
128
+ }
129
+ ],
130
+ "step_up_proof": [
131
+ {
132
+ "name": "the sensitive operation, under the passcode",
133
+ "path": "/v1/account/sensitive-echo",
134
+ "body": {
135
+ "operation": "transfer",
136
+ "probe_id": "5b0d9c4e-6f2a-4c1e-9b7d-3a8f2e1c0d9b"
137
+ },
138
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
139
+ "installation_id": "11111111-2222-4333-8444-555555555555",
140
+ "factor": "passcode",
141
+ "nonce": "yMnKy8zNzs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5uc",
142
+ "timestamp": 1760000100,
143
+ "sent_body": "{\"operation\":\"transfer\",\"probe_id\":\"5b0d9c4e-6f2a-4c1e-9b7d-3a8f2e1c0d9b\"}",
144
+ "access_proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiODEwZDIxOWQ1M2RlZTBiMmYxMWRkZWVmNDBlMTcwMDVlNDAwZTc5NTI1ZTFlOGJkOTc5MWU3MTlmNzZiZjBhOCIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6InlNbkt5OHpOenNfUTBkTFQxTlhXMTlqWjJ0dmMzZDdmNE9IaTQtVGw1dWMiLCJwYXRoIjoiL3YxL2FjY291bnQvc2Vuc2l0aXZlLWVjaG8iLCJxdWVyeSI6IiIsInRpbWVzdGFtcCI6MTc2MDAwMDEwMCwidmVyc2lvbiI6Mn0",
145
+ "proof_json": "{\"version\":2,\"purpose\":\"stepup\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"method\":\"POST\",\"path\":\"/v1/account/sensitive-echo\",\"query\":\"\",\"body_sha256\":\"810d219d53dee0b2f11ddeef40e17005e400e79525e1e8bd9791e719f76bf0a8\",\"factor\":\"passcode\",\"nonce\":\"yMnKy8zNzs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5uc\",\"timestamp\":1760000100}",
146
+ "proof": "eyJ2ZXJzaW9uIjoyLCJwdXJwb3NlIjoic3RlcHVwIiwiaW5zdGFsbGF0aW9uX2lkIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiYWNjZXNzX3Rva2VuX3NoYTI1NiI6IjE3MDViN2U4ZDViMTFlMjYxMjI0OGNlNTdlNDA3Mjc0ODIzNWJhODQ2NmFkZjVkMWFhNjg5Njk0YjEzZDBjNjkiLCJtZXRob2QiOiJQT1NUIiwicGF0aCI6Ii92MS9hY2NvdW50L3NlbnNpdGl2ZS1lY2hvIiwicXVlcnkiOiIiLCJib2R5X3NoYTI1NiI6IjgxMGQyMTlkNTNkZWUwYjJmMTFkZGVlZjQwZTE3MDA1ZTQwMGU3OTUyNWUxZThiZDk3OTFlNzE5Zjc2YmYwYTgiLCJmYWN0b3IiOiJwYXNzY29kZSIsIm5vbmNlIjoieU1uS3k4ek56c19RMGRMVDFOWFcxOWpaMnR2YzNkN2Y0T0hpNC1UbDV1YyIsInRpbWVzdGFtcCI6MTc2MDAwMDEwMH0"
147
+ },
148
+ {
149
+ "name": "a transfer whose body has text beyond ASCII, under the biometric",
150
+ "path": "/v1/account/transfer",
151
+ "body": {
152
+ "amount": 5,
153
+ "note": "café / €",
154
+ "quote": "\"x\""
155
+ },
156
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
157
+ "installation_id": "11111111-2222-4333-8444-555555555555",
158
+ "factor": "biometric",
159
+ "nonce": "6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AAECAwQFBgc",
160
+ "timestamp": 1760000101,
161
+ "sent_body": "{\"amount\":5,\"note\":\"café / €\",\"quote\":\"\\\"x\\\"\"}",
162
+ "access_proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiZjVkNmExYmE5N2FlNjFkZGEwYTJmZTVjZGRjOTg2MWYzMWVkNDlmMDQ4MDZjMzBjYzFiZmMxMjI4NTZjOTY2YiIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6IjZPbnE2LXp0N3VfdzhmTHo5UFgyOV9qNS12djhfZjdfQUFFQ0F3UUZCZ2MiLCJwYXRoIjoiL3YxL2FjY291bnQvdHJhbnNmZXIiLCJxdWVyeSI6IiIsInRpbWVzdGFtcCI6MTc2MDAwMDEwMSwidmVyc2lvbiI6Mn0",
163
+ "proof_json": "{\"version\":2,\"purpose\":\"stepup\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"method\":\"POST\",\"path\":\"/v1/account/transfer\",\"query\":\"\",\"body_sha256\":\"f5d6a1ba97ae61dda0a2fe5cddc9861f31ed49f04806c30cc1bfc122856c966b\",\"factor\":\"biometric\",\"nonce\":\"6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AAECAwQFBgc\",\"timestamp\":1760000101}",
164
+ "proof": "eyJ2ZXJzaW9uIjoyLCJwdXJwb3NlIjoic3RlcHVwIiwiaW5zdGFsbGF0aW9uX2lkIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiYWNjZXNzX3Rva2VuX3NoYTI1NiI6IjE3MDViN2U4ZDViMTFlMjYxMjI0OGNlNTdlNDA3Mjc0ODIzNWJhODQ2NmFkZjVkMWFhNjg5Njk0YjEzZDBjNjkiLCJtZXRob2QiOiJQT1NUIiwicGF0aCI6Ii92MS9hY2NvdW50L3RyYW5zZmVyIiwicXVlcnkiOiIiLCJib2R5X3NoYTI1NiI6ImY1ZDZhMWJhOTdhZTYxZGRhMGEyZmU1Y2RkYzk4NjFmMzFlZDQ5ZjA0ODA2YzMwY2MxYmZjMTIyODU2Yzk2NmIiLCJmYWN0b3IiOiJiaW9tZXRyaWMiLCJub25jZSI6IjZPbnE2LXp0N3VfdzhmTHo5UFgyOV9qNS12djhfZjdfQUFFQ0F3UUZCZ2MiLCJ0aW1lc3RhbXAiOjE3NjAwMDAxMDF9"
165
+ },
166
+ {
167
+ "name": "a session upgrade with an empty body, under the passcode",
168
+ "path": "/v1/auth/upgrade",
169
+ "body": {},
170
+ "bearer": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.eyJzdWIiOiJ2ZWN0b3IifQ.c2lnbmF0dXJl",
171
+ "installation_id": "11111111-2222-4333-8444-555555555555",
172
+ "factor": "passcode",
173
+ "nonce": "CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJic",
174
+ "timestamp": 1760000102,
175
+ "sent_body": "{}",
176
+ "access_proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiNDQxMzZmYTM1NWIzNjc4YTExNDZhZDE2ZjdlODY0OWU5NGZiNGZjMjFmZTc3ZTgzMTBjMDYwZjYxY2FhZmY4YSIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6IkNBa0tDd3dORGc4UUVSSVRGQlVXRnhnWkdoc2NIUjRmSUNFaUl5UWxKaWMiLCJwYXRoIjoiL3YxL2F1dGgvdXBncmFkZSIsInF1ZXJ5IjoiIiwidGltZXN0YW1wIjoxNzYwMDAwMTAyLCJ2ZXJzaW9uIjoyfQ",
177
+ "proof_json": "{\"version\":2,\"purpose\":\"stepup\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"access_token_sha256\":\"1705b7e8d5b11e2612248ce57e4072748235ba8466adf5d1aa689694b13d0c69\",\"method\":\"POST\",\"path\":\"/v1/auth/upgrade\",\"query\":\"\",\"body_sha256\":\"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a\",\"factor\":\"passcode\",\"nonce\":\"CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJic\",\"timestamp\":1760000102}",
178
+ "proof": "eyJ2ZXJzaW9uIjoyLCJwdXJwb3NlIjoic3RlcHVwIiwiaW5zdGFsbGF0aW9uX2lkIjoiMTExMTExMTEtMjIyMi00MzMzLTg0NDQtNTU1NTU1NTU1NTU1IiwiYWNjZXNzX3Rva2VuX3NoYTI1NiI6IjE3MDViN2U4ZDViMTFlMjYxMjI0OGNlNTdlNDA3Mjc0ODIzNWJhODQ2NmFkZjVkMWFhNjg5Njk0YjEzZDBjNjkiLCJtZXRob2QiOiJQT1NUIiwicGF0aCI6Ii92MS9hdXRoL3VwZ3JhZGUiLCJxdWVyeSI6IiIsImJvZHlfc2hhMjU2IjoiNDQxMzZmYTM1NWIzNjc4YTExNDZhZDE2ZjdlODY0OWU5NGZiNGZjMjFmZTc3ZTgzMTBjMDYwZjYxY2FhZmY4YSIsImZhY3RvciI6InBhc3Njb2RlIiwibm9uY2UiOiJDQWtLQ3d3TkRnOFFFUklURkJVV0Z4Z1pHaHNjSFI0ZklDRWlJeVFsSmljIiwidGltZXN0YW1wIjoxNzYwMDAwMTAyfQ"
179
+ }
180
+ ],
181
+ "app_pin_proof_request": [
182
+ {
183
+ "name": "the sensitive operation",
184
+ "path": "/v1/account/sensitive-echo",
185
+ "body": {
186
+ "operation": "transfer",
187
+ "probe_id": "0c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
188
+ },
189
+ "pin": "246810",
190
+ "nonce": "ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoM",
191
+ "sent_body": "{\"operation\":\"transfer\",\"probe_id\":\"0c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f\"}",
192
+ "access_proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiMzIzYTdkZDJkZDkzYmI5NTk4ZmU2NTMzZmY2ZDk5MmI4MzhhOGNkOGQ2ZjU1N2IyODY4MDQzMmY2YWQ1Y2NhNyIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6IlpHVm1aMmhwYW10c2JXNXZjSEZ5YzNSMWRuZDRlWHA3ZkgxLWY0Q0Jnb00iLCJwYXRoIjoiL3YxL2FjY291bnQvc2Vuc2l0aXZlLWVjaG8iLCJxdWVyeSI6IiIsInRpbWVzdGFtcCI6MTc2MDAwMDIwMCwidmVyc2lvbiI6Mn0",
193
+ "asked": {
194
+ "pin": "246810",
195
+ "request": {
196
+ "method": "POST",
197
+ "path": "/v1/account/sensitive-echo",
198
+ "query": "",
199
+ "body_sha256": "323a7dd2dd93bb9598fe6533ff6d992b838a8cd8d6f557b28680432f6ad5cca7",
200
+ "nonce": "ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoM"
201
+ }
202
+ },
203
+ "asked_body": "{\"pin\":\"246810\",\"request\":{\"method\":\"POST\",\"path\":\"/v1/account/sensitive-echo\",\"query\":\"\",\"body_sha256\":\"323a7dd2dd93bb9598fe6533ff6d992b838a8cd8d6f557b28680432f6ad5cca7\",\"nonce\":\"ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoM\"}}"
204
+ },
205
+ {
206
+ "name": "a transfer whose body has text beyond ASCII",
207
+ "path": "/v1/account/transfer",
208
+ "body": {
209
+ "amount": 5,
210
+ "note": "café / €",
211
+ "quote": "\"x\""
212
+ },
213
+ "pin": "246810",
214
+ "nonce": "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqM",
215
+ "sent_body": "{\"amount\":5,\"note\":\"café / €\",\"quote\":\"\\\"x\\\"\"}",
216
+ "access_proof": "eyJhY2Nlc3NfdG9rZW5fc2hhMjU2IjoiMTcwNWI3ZThkNWIxMWUyNjEyMjQ4Y2U1N2U0MDcyNzQ4MjM1YmE4NDY2YWRmNWQxYWE2ODk2OTRiMTNkMGM2OSIsImJvZHlfc2hhMjU2IjoiZjVkNmExYmE5N2FlNjFkZGEwYTJmZTVjZGRjOTg2MWYzMWVkNDlmMDQ4MDZjMzBjYzFiZmMxMjI4NTZjOTY2YiIsImluc3RhbGxhdGlvbl9pZCI6IjExMTExMTExLTIyMjItNDMzMy04NDQ0LTU1NTU1NTU1NTU1NSIsIm1ldGhvZCI6IlBPU1QiLCJub25jZSI6ImhJV0doNGlKaW91TWpZNlBrSkdTazVTVmxwZVltWnFibkoyZW42Q2hvcU0iLCJwYXRoIjoiL3YxL2FjY291bnQvdHJhbnNmZXIiLCJxdWVyeSI6IiIsInRpbWVzdGFtcCI6MTc2MDAwMDIwMSwidmVyc2lvbiI6Mn0",
217
+ "asked": {
218
+ "pin": "246810",
219
+ "request": {
220
+ "method": "POST",
221
+ "path": "/v1/account/transfer",
222
+ "query": "",
223
+ "body_sha256": "f5d6a1ba97ae61dda0a2fe5cddc9861f31ed49f04806c30cc1bfc122856c966b",
224
+ "nonce": "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqM"
225
+ }
226
+ },
227
+ "asked_body": "{\"pin\":\"246810\",\"request\":{\"method\":\"POST\",\"path\":\"/v1/account/transfer\",\"query\":\"\",\"body_sha256\":\"f5d6a1ba97ae61dda0a2fe5cddc9861f31ed49f04806c30cc1bfc122856c966b\",\"nonce\":\"hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqM\"}}"
228
+ }
229
+ ],
230
+ "step_up_reenrol_proof": [
231
+ {
232
+ "name": "a new key, the first thumbprint vector",
233
+ "installation_id": "11111111-2222-4333-8444-555555555555",
234
+ "jwk": {
235
+ "kty": "EC",
236
+ "crv": "P-256",
237
+ "alg": "ES256",
238
+ "x": "gj4omMloswXs_xmCpuJRSfT_zhni0FN7RAUphteOih4",
239
+ "y": "yi8X_0pisZv5qnqdeY_wuTEayYgtLQHC0PdeqlCPafo"
240
+ },
241
+ "stepup_key_thumbprint": "f312c43658756ed4ae5af0d111e5ed83b643f6c4fbb5dcc28f48aecafd0294e0",
242
+ "nonce": "KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkc",
243
+ "timestamp": 1760000300,
244
+ "proof_json": "{\"version\":1,\"purpose\":\"stepup_reenrol\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"stepup_key_thumbprint\":\"f312c43658756ed4ae5af0d111e5ed83b643f6c4fbb5dcc28f48aecafd0294e0\",\"nonce\":\"KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkc\",\"timestamp\":1760000300}",
245
+ "proof": "eyJ2ZXJzaW9uIjoxLCJwdXJwb3NlIjoic3RlcHVwX3JlZW5yb2wiLCJpbnN0YWxsYXRpb25faWQiOiIxMTExMTExMS0yMjIyLTQzMzMtODQ0NC01NTU1NTU1NTU1NTUiLCJzdGVwdXBfa2V5X3RodW1icHJpbnQiOiJmMzEyYzQzNjU4NzU2ZWQ0YWU1YWYwZDExMWU1ZWQ4M2I2NDNmNmM0ZmJiNWRjYzI4ZjQ4YWVjYWZkMDI5NGUwIiwibm9uY2UiOiJLQ2txS3l3dExpOHdNVEl6TkRVMk56ZzVPanM4UFQ0X1FFRkNRMFJGUmtjIiwidGltZXN0YW1wIjoxNzYwMDAwMzAwfQ"
246
+ },
247
+ {
248
+ "name": "a new key, the second thumbprint vector",
249
+ "installation_id": "11111111-2222-4333-8444-555555555555",
250
+ "jwk": {
251
+ "kty": "EC",
252
+ "crv": "P-256",
253
+ "alg": "ES256",
254
+ "x": "3AecBt0C5KPzTZLp95heI8Nr9Xmkirqarom0i4qA2XA",
255
+ "y": "TZxl4m9FWOeEc6qsaPscfUD6S7NzvO1siUIZXPWTWps"
256
+ },
257
+ "stepup_key_thumbprint": "261f0cdeeb8d013f0bd212205f97a521a744eac8743eee04d1fe73105ed36118",
258
+ "nonce": "SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmc",
259
+ "timestamp": 1760000301,
260
+ "proof_json": "{\"version\":1,\"purpose\":\"stepup_reenrol\",\"installation_id\":\"11111111-2222-4333-8444-555555555555\",\"stepup_key_thumbprint\":\"261f0cdeeb8d013f0bd212205f97a521a744eac8743eee04d1fe73105ed36118\",\"nonce\":\"SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmc\",\"timestamp\":1760000301}",
261
+ "proof": "eyJ2ZXJzaW9uIjoxLCJwdXJwb3NlIjoic3RlcHVwX3JlZW5yb2wiLCJpbnN0YWxsYXRpb25faWQiOiIxMTExMTExMS0yMjIyLTQzMzMtODQ0NC01NTU1NTU1NTU1NTUiLCJzdGVwdXBfa2V5X3RodW1icHJpbnQiOiIyNjFmMGNkZWViOGQwMTNmMGJkMjEyMjA1Zjk3YTUyMWE3NDRlYWM4NzQzZWVlMDRkMWZlNzMxMDVlZDM2MTE4Iiwibm9uY2UiOiJTRWxLUzB4TlRrOVFVVkpUVkZWV1YxaFpXbHRjWFY1ZllHRmlZMlJsWm1jIiwidGltZXN0YW1wIjoxNzYwMDAwMzAxfQ"
262
+ }
263
+ ]
264
+ }