@atproto/jwk-jose 0.1.2 → 0.1.3
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/CHANGELOG.md +11 -0
- package/dist/jose-key.d.ts +107 -7
- package/dist/jose-key.d.ts.map +1 -1
- package/dist/jose-key.js +71 -31
- package/dist/jose-key.js.map +1 -1
- package/dist/util.js +1 -2
- package/dist/util.js.map +1 -1
- package/package.json +3 -3
- package/src/jose-key.ts +95 -49
- package/tsconfig.build.tsbuildinfo +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @atproto/jwk-jose
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve compatibility with runtimes relying on webcrypto (by explicit JOSE's importJWK() "alg" argument).
|
|
8
|
+
|
|
9
|
+
- [#2879](https://github.com/bluesky-social/atproto/pull/2879) [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove unsafe type casting during JWT verification
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0), [`2889c7699`](https://github.com/bluesky-social/atproto/commit/2889c76995ce3c569f595ac3c678218e9ce659f0)]:
|
|
12
|
+
- @atproto/jwk@0.1.2
|
|
13
|
+
|
|
3
14
|
## 0.1.2
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/dist/jose-key.d.ts
CHANGED
|
@@ -1,14 +1,114 @@
|
|
|
1
|
+
import { Jwk, JwtHeader, JwtPayload, Key, SignedJwt, VerifyOptions, VerifyResult } from '@atproto/jwk';
|
|
1
2
|
import { type GenerateKeyPairOptions, type GenerateKeyPairResult, type KeyLike } from 'jose';
|
|
2
|
-
import { Jwk, JwtHeader, JwtPayload, Key, SignedJwt, VerifyOptions, VerifyPayload, VerifyResult } from '@atproto/jwk';
|
|
3
3
|
export type Importable = string | KeyLike | Jwk;
|
|
4
4
|
export type { GenerateKeyPairOptions, GenerateKeyPairResult };
|
|
5
|
-
export declare class JoseKey extends Key {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
export declare class JoseKey<J extends Jwk = Jwk> extends Key<J> {
|
|
6
|
+
/**
|
|
7
|
+
* Some runtimes (e.g. Bun) require an `alg` second argument to be set when
|
|
8
|
+
* invoking `importJWK`. In order to be compatible with these runtimes, we
|
|
9
|
+
* provide the following method to ensure the `alg` is always set. We also
|
|
10
|
+
* take the opportunity to ensure that the `alg` is compatible with this key.
|
|
11
|
+
*/
|
|
12
|
+
protected getKeyObj(alg: string): Promise<KeyLike | Uint8Array>;
|
|
13
|
+
createJwt(header: JwtHeader, payload: JwtPayload): Promise<SignedJwt>;
|
|
14
|
+
verifyJwt<C extends string = never>(token: SignedJwt, options?: VerifyOptions<C>): Promise<VerifyResult<C>>;
|
|
10
15
|
static generateKeyPair(allowedAlgos?: readonly string[], options?: GenerateKeyPairOptions): Promise<GenerateKeyPairResult<KeyLike>>;
|
|
11
|
-
static generate(allowedAlgos?: string[], kid?: string, options?: Omit<GenerateKeyPairOptions, 'extractable'>): Promise<JoseKey
|
|
16
|
+
static generate(allowedAlgos?: string[], kid?: string, options?: Omit<GenerateKeyPairOptions, 'extractable'>): Promise<JoseKey<{
|
|
17
|
+
kty: string;
|
|
18
|
+
alg?: string | undefined;
|
|
19
|
+
kid?: string | undefined;
|
|
20
|
+
ext?: boolean | undefined;
|
|
21
|
+
use?: "sig" | "enc" | undefined;
|
|
22
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
23
|
+
x5c?: string[] | undefined;
|
|
24
|
+
x5t?: string | undefined;
|
|
25
|
+
'x5t#S256'?: string | undefined;
|
|
26
|
+
x5u?: string | undefined;
|
|
27
|
+
} | {
|
|
28
|
+
kty: "RSA";
|
|
29
|
+
n: string;
|
|
30
|
+
e: string;
|
|
31
|
+
alg?: "RS256" | "RS384" | "RS512" | "PS256" | "PS384" | "PS512" | undefined;
|
|
32
|
+
kid?: string | undefined;
|
|
33
|
+
ext?: boolean | undefined;
|
|
34
|
+
use?: "sig" | "enc" | undefined;
|
|
35
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
36
|
+
x5c?: string[] | undefined;
|
|
37
|
+
x5t?: string | undefined;
|
|
38
|
+
'x5t#S256'?: string | undefined;
|
|
39
|
+
x5u?: string | undefined;
|
|
40
|
+
d?: string | undefined;
|
|
41
|
+
p?: string | undefined;
|
|
42
|
+
q?: string | undefined;
|
|
43
|
+
dp?: string | undefined;
|
|
44
|
+
dq?: string | undefined;
|
|
45
|
+
qi?: string | undefined;
|
|
46
|
+
oth?: [{
|
|
47
|
+
d?: string | undefined;
|
|
48
|
+
r?: string | undefined;
|
|
49
|
+
t?: string | undefined;
|
|
50
|
+
}, ...{
|
|
51
|
+
d?: string | undefined;
|
|
52
|
+
r?: string | undefined;
|
|
53
|
+
t?: string | undefined;
|
|
54
|
+
}[]] | undefined;
|
|
55
|
+
} | {
|
|
56
|
+
kty: "EC";
|
|
57
|
+
crv: "P-256" | "P-384" | "P-521";
|
|
58
|
+
x: string;
|
|
59
|
+
y: string;
|
|
60
|
+
alg?: "ES256" | "ES384" | "ES512" | undefined;
|
|
61
|
+
kid?: string | undefined;
|
|
62
|
+
ext?: boolean | undefined;
|
|
63
|
+
use?: "sig" | "enc" | undefined;
|
|
64
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
65
|
+
x5c?: string[] | undefined;
|
|
66
|
+
x5t?: string | undefined;
|
|
67
|
+
'x5t#S256'?: string | undefined;
|
|
68
|
+
x5u?: string | undefined;
|
|
69
|
+
d?: string | undefined;
|
|
70
|
+
} | {
|
|
71
|
+
kty: "EC";
|
|
72
|
+
crv: "secp256k1";
|
|
73
|
+
x: string;
|
|
74
|
+
y: string;
|
|
75
|
+
alg?: "ES256K" | undefined;
|
|
76
|
+
kid?: string | undefined;
|
|
77
|
+
ext?: boolean | undefined;
|
|
78
|
+
use?: "sig" | "enc" | undefined;
|
|
79
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
80
|
+
x5c?: string[] | undefined;
|
|
81
|
+
x5t?: string | undefined;
|
|
82
|
+
'x5t#S256'?: string | undefined;
|
|
83
|
+
x5u?: string | undefined;
|
|
84
|
+
d?: string | undefined;
|
|
85
|
+
} | {
|
|
86
|
+
kty: "OKP";
|
|
87
|
+
crv: "Ed25519" | "Ed448";
|
|
88
|
+
x: string;
|
|
89
|
+
alg?: "EdDSA" | undefined;
|
|
90
|
+
kid?: string | undefined;
|
|
91
|
+
ext?: boolean | undefined;
|
|
92
|
+
use?: "sig" | "enc" | undefined;
|
|
93
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
94
|
+
x5c?: string[] | undefined;
|
|
95
|
+
x5t?: string | undefined;
|
|
96
|
+
'x5t#S256'?: string | undefined;
|
|
97
|
+
x5u?: string | undefined;
|
|
98
|
+
d?: string | undefined;
|
|
99
|
+
} | {
|
|
100
|
+
kty: "oct";
|
|
101
|
+
k: string;
|
|
102
|
+
alg?: "HS256" | "HS384" | "HS512" | undefined;
|
|
103
|
+
kid?: string | undefined;
|
|
104
|
+
ext?: boolean | undefined;
|
|
105
|
+
use?: "sig" | "enc" | undefined;
|
|
106
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
107
|
+
x5c?: string[] | undefined;
|
|
108
|
+
x5t?: string | undefined;
|
|
109
|
+
'x5t#S256'?: string | undefined;
|
|
110
|
+
x5u?: string | undefined;
|
|
111
|
+
}>>;
|
|
12
112
|
static fromImportable(input: Importable, kid?: string): Promise<JoseKey>;
|
|
13
113
|
/**
|
|
14
114
|
* @see {@link exportJWK}
|
package/dist/jose-key.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jose-key.d.ts","sourceRoot":"","sources":["../src/jose-key.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jose-key.d.ts","sourceRoot":"","sources":["../src/jose-key.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EAGH,SAAS,EACT,UAAU,EAEV,GAAG,EAEH,SAAS,EACT,aAAa,EACb,YAAY,EAIb,MAAM,cAAc,CAAA;AACrB,OAAO,EAQL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAG1B,KAAK,OAAO,EACb,MAAM,MAAM,CAAA;AAMb,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,GAAG,CAAA;AAE/C,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,CAAA;AAE7D,qBAAa,OAAO,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,CAAE,SAAQ,GAAG,CAAC,CAAC,CAAC;IACtD;;;;;OAKG;cACa,SAAS,CAAC,GAAG,EAAE,MAAM;IAW/B,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAiCrE,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EACtC,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;WAyCd,eAAe,CAC1B,YAAY,GAAE,SAAS,MAAM,EAAc,EAC3C,OAAO,CAAC,EAAE,sBAAsB;WAoBrB,QAAQ,CACnB,YAAY,GAAE,MAAM,EAAc,EAClC,GAAG,CAAC,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAkFirV,CAAC;aAA+B,CAAC;aAA+B,CAAC;;aAA2C,CAAC;aAA+B,CAAC;aAA+B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAzEx4V,cAAc,CACzB,KAAK,EAAE,UAAU,EACjB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC;IA6BnB;;OAEG;WACU,WAAW,CACtB,OAAO,EAAE,OAAO,GAAG,UAAU,EAC7B,GAAG,CAAC,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC;IASnB;;OAEG;WACU,SAAS,CACpB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC;WAKN,OAAO,CAClB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;CASpB"}
|
package/dist/jose-key.js
CHANGED
|
@@ -3,52 +3,92 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.JoseKey = void 0;
|
|
4
4
|
const jwk_1 = require("@atproto/jwk");
|
|
5
5
|
const jose_1 = require("jose");
|
|
6
|
-
const jwk_2 = require("@atproto/jwk");
|
|
7
6
|
const util_1 = require("./util");
|
|
8
7
|
const { JOSEError } = jose_1.errors;
|
|
9
|
-
class JoseKey extends
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
class JoseKey extends jwk_1.Key {
|
|
9
|
+
/**
|
|
10
|
+
* Some runtimes (e.g. Bun) require an `alg` second argument to be set when
|
|
11
|
+
* invoking `importJWK`. In order to be compatible with these runtimes, we
|
|
12
|
+
* provide the following method to ensure the `alg` is always set. We also
|
|
13
|
+
* take the opportunity to ensure that the `alg` is compatible with this key.
|
|
14
|
+
*/
|
|
15
|
+
async getKeyObj(alg) {
|
|
16
|
+
if (!this.algorithms.includes(alg)) {
|
|
17
|
+
throw new jwk_1.JwkError(`Key cannot be used with algorithm "${alg}"`);
|
|
18
|
+
}
|
|
12
19
|
try {
|
|
13
|
-
return
|
|
20
|
+
return await (0, jose_1.importJWK)(this.jwk, alg);
|
|
14
21
|
}
|
|
15
22
|
catch (cause) {
|
|
16
|
-
throw new
|
|
23
|
+
throw new jwk_1.JwkError('Failed to import JWK', undefined, { cause });
|
|
17
24
|
}
|
|
18
25
|
}
|
|
19
26
|
async createJwt(header, payload) {
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
try {
|
|
28
|
+
const { kid } = header;
|
|
29
|
+
if (kid && kid !== this.kid) {
|
|
30
|
+
throw new jwk_1.JwtCreateError(`Invalid "kid" (${kid}) used to sign with key "${this.kid}"`);
|
|
31
|
+
}
|
|
32
|
+
const { alg } = header;
|
|
33
|
+
if (!alg) {
|
|
34
|
+
throw new jwk_1.JwtCreateError('Missing "alg" in JWT header');
|
|
35
|
+
}
|
|
36
|
+
const keyObj = await this.getKeyObj(alg);
|
|
37
|
+
const jwtBuilder = new jose_1.SignJWT(payload).setProtectedHeader({
|
|
38
|
+
...header,
|
|
39
|
+
alg,
|
|
40
|
+
kid: this.kid,
|
|
41
|
+
});
|
|
42
|
+
const signedJwt = await jwtBuilder.sign(keyObj);
|
|
43
|
+
return signedJwt;
|
|
22
44
|
}
|
|
23
|
-
|
|
24
|
-
|
|
45
|
+
catch (cause) {
|
|
46
|
+
if (cause instanceof JOSEError) {
|
|
47
|
+
throw new jwk_1.JwtCreateError(cause.message, cause.code, { cause });
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw jwk_1.JwtCreateError.from(cause);
|
|
51
|
+
}
|
|
25
52
|
}
|
|
26
|
-
const keyObj = await this.getKey();
|
|
27
|
-
return new jose_1.SignJWT(payload)
|
|
28
|
-
.setProtectedHeader({ ...header, kid: this.kid })
|
|
29
|
-
.sign(keyObj);
|
|
30
53
|
}
|
|
31
54
|
async verifyJwt(token, options) {
|
|
32
55
|
try {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
56
|
+
const result = await (0, jose_1.jwtVerify)(token, async ({ alg }) => this.getKeyObj(alg), { ...options, algorithms: this.algorithms });
|
|
57
|
+
// @NOTE if all tokens are signed exclusively through createJwt(), then
|
|
58
|
+
// there should be no need to parse the payload and headers here. But
|
|
59
|
+
// since the JWT could have been signed with the same key from somewhere
|
|
60
|
+
// else, let's parse it to ensure the integrity (and type safety) of the
|
|
61
|
+
// data.
|
|
62
|
+
const headerParsed = jwk_1.jwtHeaderSchema.safeParse(result.protectedHeader);
|
|
63
|
+
if (!headerParsed.success) {
|
|
64
|
+
throw new jwk_1.JwtVerifyError('Invalid JWT header', undefined, {
|
|
65
|
+
cause: headerParsed.error,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const payloadParsed = jwk_1.jwtPayloadSchema.safeParse(result.payload);
|
|
69
|
+
if (!payloadParsed.success) {
|
|
70
|
+
throw new jwk_1.JwtVerifyError('Invalid JWT payload', undefined, {
|
|
71
|
+
cause: payloadParsed.error,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
protectedHeader: headerParsed.data,
|
|
76
|
+
// "requiredClaims" enforced by jwtVerify()
|
|
77
|
+
payload: payloadParsed.data,
|
|
78
|
+
};
|
|
39
79
|
}
|
|
40
|
-
catch (
|
|
41
|
-
if (
|
|
42
|
-
throw new jwk_1.JwtVerifyError(
|
|
80
|
+
catch (cause) {
|
|
81
|
+
if (cause instanceof JOSEError) {
|
|
82
|
+
throw new jwk_1.JwtVerifyError(cause.message, cause.code, { cause });
|
|
43
83
|
}
|
|
44
84
|
else {
|
|
45
|
-
throw jwk_1.JwtVerifyError.from(
|
|
85
|
+
throw jwk_1.JwtVerifyError.from(cause);
|
|
46
86
|
}
|
|
47
87
|
}
|
|
48
88
|
}
|
|
49
89
|
static async generateKeyPair(allowedAlgos = ['ES256'], options) {
|
|
50
90
|
if (!allowedAlgos.length) {
|
|
51
|
-
throw new
|
|
91
|
+
throw new jwk_1.JwkError('No algorithms provided for key generation');
|
|
52
92
|
}
|
|
53
93
|
const errors = [];
|
|
54
94
|
for (const alg of allowedAlgos) {
|
|
@@ -59,7 +99,7 @@ class JoseKey extends jwk_2.Key {
|
|
|
59
99
|
errors.push(err);
|
|
60
100
|
}
|
|
61
101
|
}
|
|
62
|
-
throw new
|
|
102
|
+
throw new jwk_1.JwkError('Failed to generate key pair', undefined, {
|
|
63
103
|
cause: new AggregateError(errors, 'None of the algorithms worked'),
|
|
64
104
|
});
|
|
65
105
|
}
|
|
@@ -81,7 +121,7 @@ class JoseKey extends jwk_2.Key {
|
|
|
81
121
|
if (input.startsWith('{')) {
|
|
82
122
|
return this.fromJWK(input, kid);
|
|
83
123
|
}
|
|
84
|
-
throw new
|
|
124
|
+
throw new jwk_1.JwkError('Invalid input');
|
|
85
125
|
}
|
|
86
126
|
if (typeof input === 'object') {
|
|
87
127
|
// Jwk
|
|
@@ -91,7 +131,7 @@ class JoseKey extends jwk_2.Key {
|
|
|
91
131
|
// KeyLike
|
|
92
132
|
return this.fromKeyLike(input, kid);
|
|
93
133
|
}
|
|
94
|
-
throw new
|
|
134
|
+
throw new jwk_1.JwkError('Invalid input');
|
|
95
135
|
}
|
|
96
136
|
/**
|
|
97
137
|
* @see {@link exportJWK}
|
|
@@ -102,7 +142,7 @@ class JoseKey extends jwk_2.Key {
|
|
|
102
142
|
if (!jwk.alg)
|
|
103
143
|
jwk.alg = alg;
|
|
104
144
|
else if (jwk.alg !== alg)
|
|
105
|
-
throw new
|
|
145
|
+
throw new jwk_1.JwkError('Invalid "alg" in JWK');
|
|
106
146
|
}
|
|
107
147
|
return this.fromJWK(jwk, kid);
|
|
108
148
|
}
|
|
@@ -116,10 +156,10 @@ class JoseKey extends jwk_2.Key {
|
|
|
116
156
|
static async fromJWK(input, inputKid) {
|
|
117
157
|
const jwk = typeof input === 'string' ? JSON.parse(input) : input;
|
|
118
158
|
if (!jwk || typeof jwk !== 'object')
|
|
119
|
-
throw new
|
|
159
|
+
throw new jwk_1.JwkError('Invalid JWK');
|
|
120
160
|
const kid = (0, util_1.either)(jwk.kid, inputKid);
|
|
121
161
|
const use = jwk.use || 'sig';
|
|
122
|
-
return new JoseKey(
|
|
162
|
+
return new JoseKey(jwk_1.jwkValidator.parse({ ...jwk, kid, use }));
|
|
123
163
|
}
|
|
124
164
|
}
|
|
125
165
|
exports.JoseKey = JoseKey;
|
package/dist/jose-key.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jose-key.js","sourceRoot":"","sources":["../src/jose-key.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"jose-key.js","sourceRoot":"","sources":["../src/jose-key.ts"],"names":[],"mappings":"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"}
|
package/dist/util.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.either =
|
|
3
|
+
exports.either = either;
|
|
4
4
|
function either(a, b) {
|
|
5
5
|
if (a != null && b != null && a !== b) {
|
|
6
6
|
throw new TypeError(`Expected "${b}", got "${a}"`);
|
|
7
7
|
}
|
|
8
8
|
return a ?? b ?? undefined;
|
|
9
9
|
}
|
|
10
|
-
exports.either = either;
|
|
11
10
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;AAAA,wBAQC;AARD,SAAgB,MAAM,CACpB,CAAK,EACL,CAAK;IAEL,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,SAAS,CAAC,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,IAAI,SAAS,CAAA;AAC5B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/jwk-jose",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "`jose` based implementation of @atproto/jwk Key's",
|
|
6
6
|
"keywords": [
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"jose": "^5.2.0",
|
|
28
|
-
"@atproto/jwk": "0.1.
|
|
28
|
+
"@atproto/jwk": "0.1.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"typescript": "^5.
|
|
31
|
+
"typescript": "^5.6.3"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsc --build tsconfig.json"
|
package/src/jose-key.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Jwk,
|
|
3
|
+
JwkError,
|
|
4
|
+
JwtCreateError,
|
|
5
|
+
JwtHeader,
|
|
6
|
+
JwtPayload,
|
|
7
|
+
JwtVerifyError,
|
|
8
|
+
Key,
|
|
9
|
+
RequiredKey,
|
|
10
|
+
SignedJwt,
|
|
11
|
+
VerifyOptions,
|
|
12
|
+
VerifyResult,
|
|
13
|
+
jwkValidator,
|
|
14
|
+
jwtHeaderSchema,
|
|
15
|
+
jwtPayloadSchema,
|
|
16
|
+
} from '@atproto/jwk'
|
|
2
17
|
import {
|
|
3
18
|
SignJWT,
|
|
4
19
|
errors,
|
|
@@ -14,19 +29,6 @@ import {
|
|
|
14
29
|
type KeyLike,
|
|
15
30
|
} from 'jose'
|
|
16
31
|
|
|
17
|
-
import {
|
|
18
|
-
Jwk,
|
|
19
|
-
JwkError,
|
|
20
|
-
JwtCreateError,
|
|
21
|
-
JwtHeader,
|
|
22
|
-
JwtPayload,
|
|
23
|
-
Key,
|
|
24
|
-
SignedJwt,
|
|
25
|
-
VerifyOptions,
|
|
26
|
-
VerifyPayload,
|
|
27
|
-
VerifyResult,
|
|
28
|
-
jwkValidator,
|
|
29
|
-
} from '@atproto/jwk'
|
|
30
32
|
import { either } from './util'
|
|
31
33
|
|
|
32
34
|
const { JOSEError } = errors
|
|
@@ -35,53 +37,97 @@ export type Importable = string | KeyLike | Jwk
|
|
|
35
37
|
|
|
36
38
|
export type { GenerateKeyPairOptions, GenerateKeyPairResult }
|
|
37
39
|
|
|
38
|
-
export class JoseKey extends Key {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
export class JoseKey<J extends Jwk = Jwk> extends Key<J> {
|
|
41
|
+
/**
|
|
42
|
+
* Some runtimes (e.g. Bun) require an `alg` second argument to be set when
|
|
43
|
+
* invoking `importJWK`. In order to be compatible with these runtimes, we
|
|
44
|
+
* provide the following method to ensure the `alg` is always set. We also
|
|
45
|
+
* take the opportunity to ensure that the `alg` is compatible with this key.
|
|
46
|
+
*/
|
|
47
|
+
protected async getKeyObj(alg: string) {
|
|
48
|
+
if (!this.algorithms.includes(alg)) {
|
|
49
|
+
throw new JwkError(`Key cannot be used with algorithm "${alg}"`)
|
|
50
|
+
}
|
|
42
51
|
try {
|
|
43
|
-
return
|
|
52
|
+
return await importJWK(this.jwk as JWK, alg)
|
|
44
53
|
} catch (cause) {
|
|
45
54
|
throw new JwkError('Failed to import JWK', undefined, { cause })
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
async createJwt(header: JwtHeader, payload: JwtPayload) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
async createJwt(header: JwtHeader, payload: JwtPayload): Promise<SignedJwt> {
|
|
59
|
+
try {
|
|
60
|
+
const { kid } = header
|
|
61
|
+
if (kid && kid !== this.kid) {
|
|
62
|
+
throw new JwtCreateError(
|
|
63
|
+
`Invalid "kid" (${kid}) used to sign with key "${this.kid}"`,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
const { alg } = header
|
|
68
|
+
if (!alg) {
|
|
69
|
+
throw new JwtCreateError('Missing "alg" in JWT header')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const keyObj = await this.getKeyObj(alg)
|
|
73
|
+
const jwtBuilder = new SignJWT(payload).setProtectedHeader({
|
|
74
|
+
...header,
|
|
75
|
+
alg,
|
|
76
|
+
kid: this.kid,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const signedJwt = await jwtBuilder.sign(keyObj)
|
|
61
80
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
81
|
+
return signedJwt as SignedJwt
|
|
82
|
+
} catch (cause) {
|
|
83
|
+
if (cause instanceof JOSEError) {
|
|
84
|
+
throw new JwtCreateError(cause.message, cause.code, { cause })
|
|
85
|
+
} else {
|
|
86
|
+
throw JwtCreateError.from(cause)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
66
89
|
}
|
|
67
90
|
|
|
68
|
-
async verifyJwt<
|
|
69
|
-
|
|
70
|
-
C
|
|
71
|
-
|
|
91
|
+
async verifyJwt<C extends string = never>(
|
|
92
|
+
token: SignedJwt,
|
|
93
|
+
options?: VerifyOptions<C>,
|
|
94
|
+
): Promise<VerifyResult<C>> {
|
|
72
95
|
try {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
algorithms: this.algorithms,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
96
|
+
const result = await jwtVerify(
|
|
97
|
+
token,
|
|
98
|
+
async ({ alg }) => this.getKeyObj(alg),
|
|
99
|
+
{ ...options, algorithms: this.algorithms } as JWTVerifyOptions,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
// @NOTE if all tokens are signed exclusively through createJwt(), then
|
|
103
|
+
// there should be no need to parse the payload and headers here. But
|
|
104
|
+
// since the JWT could have been signed with the same key from somewhere
|
|
105
|
+
// else, let's parse it to ensure the integrity (and type safety) of the
|
|
106
|
+
// data.
|
|
107
|
+
const headerParsed = jwtHeaderSchema.safeParse(result.protectedHeader)
|
|
108
|
+
if (!headerParsed.success) {
|
|
109
|
+
throw new JwtVerifyError('Invalid JWT header', undefined, {
|
|
110
|
+
cause: headerParsed.error,
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const payloadParsed = jwtPayloadSchema.safeParse(result.payload)
|
|
115
|
+
if (!payloadParsed.success) {
|
|
116
|
+
throw new JwtVerifyError('Invalid JWT payload', undefined, {
|
|
117
|
+
cause: payloadParsed.error,
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
protectedHeader: headerParsed.data,
|
|
123
|
+
// "requiredClaims" enforced by jwtVerify()
|
|
124
|
+
payload: payloadParsed.data as RequiredKey<JwtPayload, C>,
|
|
125
|
+
}
|
|
126
|
+
} catch (cause) {
|
|
127
|
+
if (cause instanceof JOSEError) {
|
|
128
|
+
throw new JwtVerifyError(cause.message, cause.code, { cause })
|
|
83
129
|
} else {
|
|
84
|
-
throw JwtVerifyError.from(
|
|
130
|
+
throw JwtVerifyError.from(cause)
|
|
85
131
|
}
|
|
86
132
|
}
|
|
87
133
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/index.ts","./src/jose-key.ts","./src/util.ts"],"version":"5.6.3"}
|