@atcute/oauth-crypto 0.1.0

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 (118) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +7 -0
  3. package/dist/client-assertion/create-client-assertion.d.ts +19 -0
  4. package/dist/client-assertion/create-client-assertion.d.ts.map +1 -0
  5. package/dist/client-assertion/create-client-assertion.js +34 -0
  6. package/dist/client-assertion/create-client-assertion.js.map +1 -0
  7. package/dist/client-assertion/generate-key.d.ts +11 -0
  8. package/dist/client-assertion/generate-key.d.ts.map +1 -0
  9. package/dist/client-assertion/generate-key.js +18 -0
  10. package/dist/client-assertion/generate-key.js.map +1 -0
  11. package/dist/client-assertion/index.d.ts +5 -0
  12. package/dist/client-assertion/index.d.ts.map +1 -0
  13. package/dist/client-assertion/index.js +4 -0
  14. package/dist/client-assertion/index.js.map +1 -0
  15. package/dist/client-assertion/keys.d.ts +14 -0
  16. package/dist/client-assertion/keys.d.ts.map +1 -0
  17. package/dist/client-assertion/keys.js +18 -0
  18. package/dist/client-assertion/keys.js.map +1 -0
  19. package/dist/client-assertion/types.d.ts +9 -0
  20. package/dist/client-assertion/types.d.ts.map +1 -0
  21. package/dist/client-assertion/types.js +2 -0
  22. package/dist/client-assertion/types.js.map +1 -0
  23. package/dist/dpop/fetch.d.ts +24 -0
  24. package/dist/dpop/fetch.d.ts.map +1 -0
  25. package/dist/dpop/fetch.js +102 -0
  26. package/dist/dpop/fetch.js.map +1 -0
  27. package/dist/dpop/generate-key.d.ts +9 -0
  28. package/dist/dpop/generate-key.d.ts.map +1 -0
  29. package/dist/dpop/generate-key.js +61 -0
  30. package/dist/dpop/generate-key.js.map +1 -0
  31. package/dist/dpop/index.d.ts +6 -0
  32. package/dist/dpop/index.d.ts.map +1 -0
  33. package/dist/dpop/index.js +5 -0
  34. package/dist/dpop/index.js.map +1 -0
  35. package/dist/dpop/proof.d.ts +9 -0
  36. package/dist/dpop/proof.d.ts.map +1 -0
  37. package/dist/dpop/proof.js +36 -0
  38. package/dist/dpop/proof.js.map +1 -0
  39. package/dist/dpop/types.d.ts +17 -0
  40. package/dist/dpop/types.d.ts.map +1 -0
  41. package/dist/dpop/types.js +2 -0
  42. package/dist/dpop/types.js.map +1 -0
  43. package/dist/dpop/verify.d.ts +42 -0
  44. package/dist/dpop/verify.d.ts.map +1 -0
  45. package/dist/dpop/verify.js +124 -0
  46. package/dist/dpop/verify.js.map +1 -0
  47. package/dist/hash/index.d.ts +3 -0
  48. package/dist/hash/index.d.ts.map +1 -0
  49. package/dist/hash/index.js +3 -0
  50. package/dist/hash/index.js.map +1 -0
  51. package/dist/hash/pkce.d.ts +12 -0
  52. package/dist/hash/pkce.d.ts.map +1 -0
  53. package/dist/hash/pkce.js +14 -0
  54. package/dist/hash/pkce.js.map +1 -0
  55. package/dist/hash/sha256.d.ts +8 -0
  56. package/dist/hash/sha256.d.ts.map +1 -0
  57. package/dist/hash/sha256.js +14 -0
  58. package/dist/hash/sha256.js.map +1 -0
  59. package/dist/index.d.ts +6 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +6 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/internal/crypto.d.ts +7 -0
  64. package/dist/internal/crypto.d.ts.map +1 -0
  65. package/dist/internal/crypto.js +78 -0
  66. package/dist/internal/crypto.js.map +1 -0
  67. package/dist/internal/jwk.d.ts +10 -0
  68. package/dist/internal/jwk.d.ts.map +1 -0
  69. package/dist/internal/jwk.js +121 -0
  70. package/dist/internal/jwk.js.map +1 -0
  71. package/dist/internal/key-cache.d.ts +24 -0
  72. package/dist/internal/key-cache.d.ts.map +1 -0
  73. package/dist/internal/key-cache.js +36 -0
  74. package/dist/internal/key-cache.js.map +1 -0
  75. package/dist/jwk/compute-jkt.d.ts +9 -0
  76. package/dist/jwk/compute-jkt.d.ts.map +1 -0
  77. package/dist/jwk/compute-jkt.js +23 -0
  78. package/dist/jwk/compute-jkt.js.map +1 -0
  79. package/dist/jwk/index.d.ts +5 -0
  80. package/dist/jwk/index.d.ts.map +1 -0
  81. package/dist/jwk/index.js +4 -0
  82. package/dist/jwk/index.js.map +1 -0
  83. package/dist/jwk/keys.d.ts +9 -0
  84. package/dist/jwk/keys.d.ts.map +1 -0
  85. package/dist/jwk/keys.js +13 -0
  86. package/dist/jwk/keys.js.map +1 -0
  87. package/dist/jwk/types.d.ts +37 -0
  88. package/dist/jwk/types.d.ts.map +1 -0
  89. package/dist/jwk/types.js +2 -0
  90. package/dist/jwk/types.js.map +1 -0
  91. package/dist/jwt/index.d.ts +26 -0
  92. package/dist/jwt/index.d.ts.map +1 -0
  93. package/dist/jwt/index.js +56 -0
  94. package/dist/jwt/index.js.map +1 -0
  95. package/lib/client-assertion/create-client-assertion.ts +50 -0
  96. package/lib/client-assertion/generate-key.ts +26 -0
  97. package/lib/client-assertion/index.ts +4 -0
  98. package/lib/client-assertion/keys.ts +26 -0
  99. package/lib/client-assertion/types.ts +9 -0
  100. package/lib/dpop/fetch.ts +140 -0
  101. package/lib/dpop/generate-key.ts +72 -0
  102. package/lib/dpop/index.ts +11 -0
  103. package/lib/dpop/proof.ts +46 -0
  104. package/lib/dpop/types.ts +19 -0
  105. package/lib/dpop/verify.ts +169 -0
  106. package/lib/hash/index.ts +2 -0
  107. package/lib/hash/pkce.ts +18 -0
  108. package/lib/hash/sha256.ts +14 -0
  109. package/lib/index.ts +5 -0
  110. package/lib/internal/crypto.ts +92 -0
  111. package/lib/internal/jwk.ts +157 -0
  112. package/lib/internal/key-cache.ts +51 -0
  113. package/lib/jwk/compute-jkt.ts +27 -0
  114. package/lib/jwk/index.ts +12 -0
  115. package/lib/jwk/keys.ts +15 -0
  116. package/lib/jwk/types.ts +51 -0
  117. package/lib/jwt/index.ts +86 -0
  118. package/package.json +38 -0
@@ -0,0 +1,86 @@
1
+ import { fromBase64Url, toBase64Url } from '@atcute/multibase';
2
+ import { decodeUtf8From, encodeUtf8 } from '@atcute/uint8array';
3
+
4
+ import { getSignAlgorithm } from '../internal/crypto.js';
5
+ import type { SigningAlgorithm } from '../jwk/types.js';
6
+
7
+ /**
8
+ * signs a jwt using webcrypto.
9
+ *
10
+ * @param params signing parameters
11
+ * @returns signed jwt
12
+ */
13
+ export const signJwt = async (params: {
14
+ header: Record<string, unknown>;
15
+ payload: Record<string, unknown>;
16
+ key: CryptoKey;
17
+ alg: SigningAlgorithm;
18
+ }): Promise<string> => {
19
+ const { header, payload, key, alg } = params;
20
+ const fullHeader = { ...header, alg };
21
+ const headerSegment = encodeSegment(fullHeader);
22
+ const payloadSegment = encodeSegment(payload);
23
+ const signingInput = `${headerSegment}.${payloadSegment}`;
24
+
25
+ const signature = await crypto.subtle.sign(
26
+ getSignAlgorithm(alg),
27
+ key,
28
+ encodeUtf8(signingInput) as Uint8Array<ArrayBuffer>,
29
+ );
30
+
31
+ const signatureSegment = toBase64Url(new Uint8Array(signature));
32
+
33
+ return `${signingInput}.${signatureSegment}`;
34
+ };
35
+
36
+ /**
37
+ * verifies a jwt and returns its payload.
38
+ *
39
+ * @param jwt jwt string
40
+ * @param options verification options
41
+ * @returns decoded payload
42
+ */
43
+ export const verifyJwt = async (
44
+ jwt: string,
45
+ options: { key: CryptoKey; alg: SigningAlgorithm; typ?: string },
46
+ ): Promise<Record<string, unknown>> => {
47
+ const { key, alg, typ } = options;
48
+ const parts = jwt.split('.');
49
+ if (parts.length !== 3) {
50
+ throw new Error(`invalid jwt format`);
51
+ }
52
+
53
+ const header = decodeSegment<Record<string, unknown>>(parts[0]);
54
+ if (header.alg !== alg) {
55
+ throw new Error(`invalid jwt alg`);
56
+ }
57
+ if (typ && header.typ !== typ) {
58
+ throw new Error(`invalid jwt typ`);
59
+ }
60
+
61
+ const payload = decodeSegment<Record<string, unknown>>(parts[1]);
62
+ const signature = fromBase64Url(parts[2]);
63
+ const signingInput = `${parts[0]}.${parts[1]}`;
64
+
65
+ const ok = await crypto.subtle.verify(
66
+ getSignAlgorithm(alg),
67
+ key,
68
+ signature,
69
+ encodeUtf8(signingInput) as Uint8Array<ArrayBuffer>,
70
+ );
71
+
72
+ if (!ok) {
73
+ throw new Error(`invalid jwt signature`);
74
+ }
75
+
76
+ return payload;
77
+ };
78
+
79
+ const encodeSegment = (value: unknown): string => {
80
+ return toBase64Url(encodeUtf8(JSON.stringify(value)));
81
+ };
82
+
83
+ const decodeSegment = <T>(value: string): T => {
84
+ const bytes = fromBase64Url(value);
85
+ return JSON.parse(decodeUtf8From(bytes)) as T;
86
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@atcute/oauth-crypto",
3
+ "version": "0.1.0",
4
+ "description": "crypto helpers for AT Protocol OAuth",
5
+ "license": "0BSD",
6
+ "repository": {
7
+ "url": "https://github.com/mary-ext/atcute",
8
+ "directory": "packages/oauth/crypto"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "lib/",
13
+ "!lib/**/*.bench.ts",
14
+ "!lib/**/*.test.ts"
15
+ ],
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": "./dist/index.js"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "dependencies": {
25
+ "@badrap/valita": "^0.4.6",
26
+ "nanoid": "^5.1.6",
27
+ "@atcute/multibase": "^1.1.7",
28
+ "@atcute/uint8array": "^1.1.0"
29
+ },
30
+ "devDependencies": {
31
+ "vitest": "^4.0.16"
32
+ },
33
+ "scripts": {
34
+ "build": "tsgo --project tsconfig.build.json",
35
+ "test": "vitest",
36
+ "prepublish": "rm -rf dist; pnpm run build"
37
+ }
38
+ }