@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.
- package/LICENSE +14 -0
- package/README.md +7 -0
- package/dist/client-assertion/create-client-assertion.d.ts +19 -0
- package/dist/client-assertion/create-client-assertion.d.ts.map +1 -0
- package/dist/client-assertion/create-client-assertion.js +34 -0
- package/dist/client-assertion/create-client-assertion.js.map +1 -0
- package/dist/client-assertion/generate-key.d.ts +11 -0
- package/dist/client-assertion/generate-key.d.ts.map +1 -0
- package/dist/client-assertion/generate-key.js +18 -0
- package/dist/client-assertion/generate-key.js.map +1 -0
- package/dist/client-assertion/index.d.ts +5 -0
- package/dist/client-assertion/index.d.ts.map +1 -0
- package/dist/client-assertion/index.js +4 -0
- package/dist/client-assertion/index.js.map +1 -0
- package/dist/client-assertion/keys.d.ts +14 -0
- package/dist/client-assertion/keys.d.ts.map +1 -0
- package/dist/client-assertion/keys.js +18 -0
- package/dist/client-assertion/keys.js.map +1 -0
- package/dist/client-assertion/types.d.ts +9 -0
- package/dist/client-assertion/types.d.ts.map +1 -0
- package/dist/client-assertion/types.js +2 -0
- package/dist/client-assertion/types.js.map +1 -0
- package/dist/dpop/fetch.d.ts +24 -0
- package/dist/dpop/fetch.d.ts.map +1 -0
- package/dist/dpop/fetch.js +102 -0
- package/dist/dpop/fetch.js.map +1 -0
- package/dist/dpop/generate-key.d.ts +9 -0
- package/dist/dpop/generate-key.d.ts.map +1 -0
- package/dist/dpop/generate-key.js +61 -0
- package/dist/dpop/generate-key.js.map +1 -0
- package/dist/dpop/index.d.ts +6 -0
- package/dist/dpop/index.d.ts.map +1 -0
- package/dist/dpop/index.js +5 -0
- package/dist/dpop/index.js.map +1 -0
- package/dist/dpop/proof.d.ts +9 -0
- package/dist/dpop/proof.d.ts.map +1 -0
- package/dist/dpop/proof.js +36 -0
- package/dist/dpop/proof.js.map +1 -0
- package/dist/dpop/types.d.ts +17 -0
- package/dist/dpop/types.d.ts.map +1 -0
- package/dist/dpop/types.js +2 -0
- package/dist/dpop/types.js.map +1 -0
- package/dist/dpop/verify.d.ts +42 -0
- package/dist/dpop/verify.d.ts.map +1 -0
- package/dist/dpop/verify.js +124 -0
- package/dist/dpop/verify.js.map +1 -0
- package/dist/hash/index.d.ts +3 -0
- package/dist/hash/index.d.ts.map +1 -0
- package/dist/hash/index.js +3 -0
- package/dist/hash/index.js.map +1 -0
- package/dist/hash/pkce.d.ts +12 -0
- package/dist/hash/pkce.d.ts.map +1 -0
- package/dist/hash/pkce.js +14 -0
- package/dist/hash/pkce.js.map +1 -0
- package/dist/hash/sha256.d.ts +8 -0
- package/dist/hash/sha256.d.ts.map +1 -0
- package/dist/hash/sha256.js +14 -0
- package/dist/hash/sha256.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/crypto.d.ts +7 -0
- package/dist/internal/crypto.d.ts.map +1 -0
- package/dist/internal/crypto.js +78 -0
- package/dist/internal/crypto.js.map +1 -0
- package/dist/internal/jwk.d.ts +10 -0
- package/dist/internal/jwk.d.ts.map +1 -0
- package/dist/internal/jwk.js +121 -0
- package/dist/internal/jwk.js.map +1 -0
- package/dist/internal/key-cache.d.ts +24 -0
- package/dist/internal/key-cache.d.ts.map +1 -0
- package/dist/internal/key-cache.js +36 -0
- package/dist/internal/key-cache.js.map +1 -0
- package/dist/jwk/compute-jkt.d.ts +9 -0
- package/dist/jwk/compute-jkt.d.ts.map +1 -0
- package/dist/jwk/compute-jkt.js +23 -0
- package/dist/jwk/compute-jkt.js.map +1 -0
- package/dist/jwk/index.d.ts +5 -0
- package/dist/jwk/index.d.ts.map +1 -0
- package/dist/jwk/index.js +4 -0
- package/dist/jwk/index.js.map +1 -0
- package/dist/jwk/keys.d.ts +9 -0
- package/dist/jwk/keys.d.ts.map +1 -0
- package/dist/jwk/keys.js +13 -0
- package/dist/jwk/keys.js.map +1 -0
- package/dist/jwk/types.d.ts +37 -0
- package/dist/jwk/types.d.ts.map +1 -0
- package/dist/jwk/types.js +2 -0
- package/dist/jwk/types.js.map +1 -0
- package/dist/jwt/index.d.ts +26 -0
- package/dist/jwt/index.d.ts.map +1 -0
- package/dist/jwt/index.js +56 -0
- package/dist/jwt/index.js.map +1 -0
- package/lib/client-assertion/create-client-assertion.ts +50 -0
- package/lib/client-assertion/generate-key.ts +26 -0
- package/lib/client-assertion/index.ts +4 -0
- package/lib/client-assertion/keys.ts +26 -0
- package/lib/client-assertion/types.ts +9 -0
- package/lib/dpop/fetch.ts +140 -0
- package/lib/dpop/generate-key.ts +72 -0
- package/lib/dpop/index.ts +11 -0
- package/lib/dpop/proof.ts +46 -0
- package/lib/dpop/types.ts +19 -0
- package/lib/dpop/verify.ts +169 -0
- package/lib/hash/index.ts +2 -0
- package/lib/hash/pkce.ts +18 -0
- package/lib/hash/sha256.ts +14 -0
- package/lib/index.ts +5 -0
- package/lib/internal/crypto.ts +92 -0
- package/lib/internal/jwk.ts +157 -0
- package/lib/internal/key-cache.ts +51 -0
- package/lib/jwk/compute-jkt.ts +27 -0
- package/lib/jwk/index.ts +12 -0
- package/lib/jwk/keys.ts +15 -0
- package/lib/jwk/types.ts +51 -0
- package/lib/jwt/index.ts +86 -0
- package/package.json +38 -0
package/lib/jwt/index.ts
ADDED
|
@@ -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
|
+
}
|