@saurbit/oauth2-jwt 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 +21 -0
- package/README.md +152 -0
- package/esm/jose_jwks_authority.d.ts +90 -0
- package/esm/jose_jwks_authority.d.ts.map +1 -0
- package/esm/jose_jwks_authority.js +214 -0
- package/esm/jwks_key_store.d.ts +53 -0
- package/esm/jwks_key_store.d.ts.map +1 -0
- package/esm/jwks_key_store.js +86 -0
- package/esm/jwks_rotator.d.ts +36 -0
- package/esm/jwks_rotator.d.ts.map +1 -0
- package/esm/jwks_rotator.js +54 -0
- package/esm/methods.d.ts +39 -0
- package/esm/methods.d.ts.map +1 -0
- package/esm/methods.js +52 -0
- package/esm/mod.d.ts +6 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +4 -0
- package/esm/package.json +3 -0
- package/esm/types.d.ts +179 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/types.js +1 -0
- package/package.json +33 -0
- package/script/jose_jwks_authority.d.ts +90 -0
- package/script/jose_jwks_authority.d.ts.map +1 -0
- package/script/jose_jwks_authority.js +218 -0
- package/script/jwks_key_store.d.ts +53 -0
- package/script/jwks_key_store.d.ts.map +1 -0
- package/script/jwks_key_store.js +91 -0
- package/script/jwks_rotator.d.ts +36 -0
- package/script/jwks_rotator.d.ts.map +1 -0
- package/script/jwks_rotator.js +58 -0
- package/script/methods.d.ts +39 -0
- package/script/methods.d.ts.map +1 -0
- package/script/methods.js +58 -0
- package/script/mod.d.ts +6 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +14 -0
- package/script/package.json +3 -0
- package/script/types.d.ts +179 -0
- package/script/types.d.ts.map +1 -0
- package/script/types.js +2 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages automatic JWKS key rotation based on a configurable interval.
|
|
3
|
+
*
|
|
4
|
+
* Call {@link JwksRotator.checkAndRotateKeys} at service startup and/or on a
|
|
5
|
+
* recurring schedule (e.g. every hour) to ensure that signing keys are rotated
|
|
6
|
+
* before they expire. During rotation the previous public key remains available
|
|
7
|
+
* in the JWKS until its TTL expires, so in-flight tokens continue to verify correctly.
|
|
8
|
+
*/
|
|
9
|
+
export class JwksRotator {
|
|
10
|
+
/**
|
|
11
|
+
* @param options - Rotation configuration: key generator, timestamp store, and interval.
|
|
12
|
+
*/
|
|
13
|
+
constructor({ keyGenerator, rotationIntervalMs, rotatorKeyStore }) {
|
|
14
|
+
Object.defineProperty(this, "keyGenerator", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: void 0
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(this, "rotatorKeyStore", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true,
|
|
24
|
+
value: void 0
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(this, "rotationIntervalMs", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
this.keyGenerator = keyGenerator;
|
|
33
|
+
this.rotationIntervalMs = rotationIntervalMs;
|
|
34
|
+
this.rotatorKeyStore = rotatorKeyStore;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Checks if rotation is due, and performs rotation if necessary.
|
|
38
|
+
* Should be called at service startup or on a schedule (e.g. every hour).
|
|
39
|
+
*/
|
|
40
|
+
async checkAndRotateKeys() {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const lastRotation = await this.rotatorKeyStore.getLastRotationTimestamp();
|
|
43
|
+
if (isNaN(lastRotation) || now - lastRotation >= this.rotationIntervalMs) {
|
|
44
|
+
await this.rotateKeys();
|
|
45
|
+
await this.rotatorKeyStore.setLastRotationTimestamp(now);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const _nextIn = this.rotationIntervalMs - (now - lastRotation);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async rotateKeys() {
|
|
52
|
+
await this.keyGenerator.generateKeyPair();
|
|
53
|
+
}
|
|
54
|
+
}
|
package/esm/methods.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { JwkVerify, JwtDecode, JwtVerify } from "@saurbit/oauth2";
|
|
2
|
+
/**
|
|
3
|
+
* Verifies a JWT using the provided secret or key and returns the decoded payload.
|
|
4
|
+
* Wraps [jose](https://github.com/panva/jose)'s `jwtVerify`.
|
|
5
|
+
*
|
|
6
|
+
* Pass this as the `JwtVerify` argument to `ClientSecretJwt` or `PrivateKeyJwt`
|
|
7
|
+
* from `@saurbit/oauth2`.
|
|
8
|
+
*
|
|
9
|
+
* @param jwt - The compact serialized JWT to verify.
|
|
10
|
+
* @param secretOrKey - The secret (`string` / `Uint8Array`) or `CryptoKey` for verification.
|
|
11
|
+
* @param options - Optional jose verification options (algorithms, audience, issuer, etc.).
|
|
12
|
+
* @returns The verified JWT payload.
|
|
13
|
+
* @throws If the token is invalid, expired, or the signature does not match.
|
|
14
|
+
*/
|
|
15
|
+
export declare const verifyJwt: JwtVerify;
|
|
16
|
+
/**
|
|
17
|
+
* Decodes a JWT payload **without** verifying its signature.
|
|
18
|
+
* Wraps [jose](https://github.com/panva/jose)'s `decodeJwt`.
|
|
19
|
+
*
|
|
20
|
+
* Pass this as the `JwtDecode` argument to `ClientSecretJwt` or `PrivateKeyJwt`
|
|
21
|
+
* from `@saurbit/oauth2`.
|
|
22
|
+
*
|
|
23
|
+
* @param jwt - The compact serialized JWT to decode.
|
|
24
|
+
* @returns The decoded JWT payload (unverified).
|
|
25
|
+
*/
|
|
26
|
+
export declare const decodeJwt: JwtDecode;
|
|
27
|
+
/**
|
|
28
|
+
* Verifies a JWT whose header embeds the public JWK (`"jwk"` header parameter).
|
|
29
|
+
* The public key is extracted from the JWT header itself and used to verify the signature.
|
|
30
|
+
* Only `ES256` algorithm tokens are accepted.
|
|
31
|
+
*
|
|
32
|
+
* Pass this as the `JwkVerify` argument to `DPoPTokenType` from `@saurbit/oauth2`.
|
|
33
|
+
*
|
|
34
|
+
* @param token - The compact serialized JWT (DPoP proof) to verify.
|
|
35
|
+
* @returns The verified JWT payload.
|
|
36
|
+
* @throws If the token is invalid, the `jwk` header is missing, or signature verification fails.
|
|
37
|
+
*/
|
|
38
|
+
export declare const verifyJwk: JwkVerify;
|
|
39
|
+
//# sourceMappingURL=methods.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../src/methods.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGvE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,EAAE,SAGvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,EAAE,SAEvB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,EAAE,SAYvB,CAAC"}
|
package/esm/methods.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { decodeJwt as joseDecodeJwt, importJWK, jwtVerify } from "jose";
|
|
2
|
+
/**
|
|
3
|
+
* Verifies a JWT using the provided secret or key and returns the decoded payload.
|
|
4
|
+
* Wraps [jose](https://github.com/panva/jose)'s `jwtVerify`.
|
|
5
|
+
*
|
|
6
|
+
* Pass this as the `JwtVerify` argument to `ClientSecretJwt` or `PrivateKeyJwt`
|
|
7
|
+
* from `@saurbit/oauth2`.
|
|
8
|
+
*
|
|
9
|
+
* @param jwt - The compact serialized JWT to verify.
|
|
10
|
+
* @param secretOrKey - The secret (`string` / `Uint8Array`) or `CryptoKey` for verification.
|
|
11
|
+
* @param options - Optional jose verification options (algorithms, audience, issuer, etc.).
|
|
12
|
+
* @returns The verified JWT payload.
|
|
13
|
+
* @throws If the token is invalid, expired, or the signature does not match.
|
|
14
|
+
*/
|
|
15
|
+
export const verifyJwt = async (jwt, secretOrKey, options) => {
|
|
16
|
+
const { payload } = await jwtVerify(jwt, secretOrKey, options);
|
|
17
|
+
return payload;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Decodes a JWT payload **without** verifying its signature.
|
|
21
|
+
* Wraps [jose](https://github.com/panva/jose)'s `decodeJwt`.
|
|
22
|
+
*
|
|
23
|
+
* Pass this as the `JwtDecode` argument to `ClientSecretJwt` or `PrivateKeyJwt`
|
|
24
|
+
* from `@saurbit/oauth2`.
|
|
25
|
+
*
|
|
26
|
+
* @param jwt - The compact serialized JWT to decode.
|
|
27
|
+
* @returns The decoded JWT payload (unverified).
|
|
28
|
+
*/
|
|
29
|
+
export const decodeJwt = (jwt) => {
|
|
30
|
+
return joseDecodeJwt(jwt);
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Verifies a JWT whose header embeds the public JWK (`"jwk"` header parameter).
|
|
34
|
+
* The public key is extracted from the JWT header itself and used to verify the signature.
|
|
35
|
+
* Only `ES256` algorithm tokens are accepted.
|
|
36
|
+
*
|
|
37
|
+
* Pass this as the `JwkVerify` argument to `DPoPTokenType` from `@saurbit/oauth2`.
|
|
38
|
+
*
|
|
39
|
+
* @param token - The compact serialized JWT (DPoP proof) to verify.
|
|
40
|
+
* @returns The verified JWT payload.
|
|
41
|
+
* @throws If the token is invalid, the `jwk` header is missing, or signature verification fails.
|
|
42
|
+
*/
|
|
43
|
+
export const verifyJwk = async (token) => {
|
|
44
|
+
const { payload } = await jwtVerify(token, (header) => {
|
|
45
|
+
if (!header.jwk)
|
|
46
|
+
throw new Error("Missing JWK");
|
|
47
|
+
return importJWK(header.jwk, header.alg);
|
|
48
|
+
}, {
|
|
49
|
+
algorithms: ["ES256"],
|
|
50
|
+
});
|
|
51
|
+
return payload;
|
|
52
|
+
};
|
package/esm/mod.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { JoseJwksAuthority } from "./jose_jwks_authority.js";
|
|
2
|
+
export { createInMemoryKeyStore, InMemoryKeyStore } from "./jwks_key_store.js";
|
|
3
|
+
export { JwksRotator, type JwksRotatorOptions } from "./jwks_rotator.js";
|
|
4
|
+
export { decodeJwt, verifyJwk, verifyJwt } from "./methods.js";
|
|
5
|
+
export type { JwksKeyStore, JwksRotationTimestampStore, JwtAuthority, JwtSigner, JwtVerifier, KeyGenerator, RawKey, RSA, } from "./types.js";
|
|
6
|
+
//# sourceMappingURL=mod.d.ts.map
|
package/esm/mod.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE/D,YAAY,EACV,YAAY,EACZ,0BAA0B,EAC1B,YAAY,EACZ,SAAS,EACT,WAAW,EACX,YAAY,EACZ,MAAM,EACN,GAAG,GACJ,MAAM,YAAY,CAAC"}
|
package/esm/mod.js
ADDED
package/esm/package.json
ADDED
package/esm/types.d.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { JWTPayload } from "jose";
|
|
2
|
+
/**
|
|
3
|
+
* Represents an RSA public or private key in JSON Web Key (JWK) format.
|
|
4
|
+
*
|
|
5
|
+
* When used as a public key only `kty`, `e`, and `n` are present.
|
|
6
|
+
* The private key fields (`d`, `p`, `q`, `dp`, `dq`, `qi`) are included on private keys.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc7517} JSON Web Key (JWK)
|
|
9
|
+
*/
|
|
10
|
+
export interface RSA {
|
|
11
|
+
/** Key type. Always `"RSA"` for RSA keys. */
|
|
12
|
+
kty: "RSA";
|
|
13
|
+
/** RSA public exponent, Base64URL-encoded. */
|
|
14
|
+
e: string;
|
|
15
|
+
/** RSA modulus, Base64URL-encoded. */
|
|
16
|
+
n: string;
|
|
17
|
+
/** RSA private exponent, Base64URL-encoded. Present only on private keys. */
|
|
18
|
+
d?: string | undefined;
|
|
19
|
+
/** First prime factor, Base64URL-encoded. Present only on private keys. */
|
|
20
|
+
p?: string | undefined;
|
|
21
|
+
/** Second prime factor, Base64URL-encoded. Present only on private keys. */
|
|
22
|
+
q?: string | undefined;
|
|
23
|
+
/** First factor CRT exponent, Base64URL-encoded. Present only on private keys. */
|
|
24
|
+
dp?: string | undefined;
|
|
25
|
+
/** Second factor CRT exponent, Base64URL-encoded. Present only on private keys. */
|
|
26
|
+
dq?: string | undefined;
|
|
27
|
+
/** First CRT coefficient, Base64URL-encoded. Present only on private keys. */
|
|
28
|
+
qi?: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Represents a public key as exposed in a JSON Web Key Set (JWKS).
|
|
32
|
+
* This is the format returned by the JWKS endpoint and used by JWT verifiers
|
|
33
|
+
* to validate token signatures.
|
|
34
|
+
*
|
|
35
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc7517} JSON Web Key (JWK)
|
|
36
|
+
*/
|
|
37
|
+
export interface RawKey {
|
|
38
|
+
/** The algorithm intended for use with this key (e.g. `"RS256"`). */
|
|
39
|
+
alg: string;
|
|
40
|
+
/** Key type (e.g. `"RSA"`). */
|
|
41
|
+
kty: string;
|
|
42
|
+
/** Intended use of the key: signature (`"sig"`), encryption (`"enc"`), or description (`"desc"`). */
|
|
43
|
+
use: "sig" | "enc" | "desc";
|
|
44
|
+
/** Key ID - a unique identifier used to match a JWT `kid` header to the correct public key. */
|
|
45
|
+
kid: string;
|
|
46
|
+
/** RSA public exponent, Base64URL-encoded. Together with `n`, forms the RSA public key. */
|
|
47
|
+
e: string;
|
|
48
|
+
/** RSA modulus, Base64URL-encoded. Together with `e`, forms the RSA public key. */
|
|
49
|
+
n: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Persists the timestamp of the last JWKS key rotation.
|
|
53
|
+
* Used by {@link JwksRotator} to determine when the next rotation is due.
|
|
54
|
+
*
|
|
55
|
+
* Implement this interface backed by a persistent or distributed store
|
|
56
|
+
* (e.g. Redis, database) when running multiple service instances.
|
|
57
|
+
*/
|
|
58
|
+
export interface JwksRotationTimestampStore {
|
|
59
|
+
/**
|
|
60
|
+
* Retrieves the Unix timestamp (in milliseconds) of the last key rotation.
|
|
61
|
+
* @returns The timestamp of the last rotation, or `0` if no rotation has occurred.
|
|
62
|
+
*/
|
|
63
|
+
getLastRotationTimestamp(): Promise<number>;
|
|
64
|
+
/**
|
|
65
|
+
* Persists the Unix timestamp (in milliseconds) of the most recent key rotation.
|
|
66
|
+
* @param rotationTimestamp - The timestamp to store.
|
|
67
|
+
*/
|
|
68
|
+
setLastRotationTimestamp(rotationTimestamp: number): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Persists the active signing key pair and the set of valid public keys
|
|
72
|
+
* that are exposed via the JWKS endpoint.
|
|
73
|
+
*
|
|
74
|
+
* Implement this interface backed by a persistent or distributed store
|
|
75
|
+
* (e.g. Redis, database) when running multiple service instances.
|
|
76
|
+
* The built-in {@link InMemoryKeyStore} is suitable for single-process deployments.
|
|
77
|
+
*/
|
|
78
|
+
export interface JwksKeyStore {
|
|
79
|
+
/**
|
|
80
|
+
* Stores the current active private key and its corresponding public key.
|
|
81
|
+
* The public key will be kept for the duration of the TTL for JWKS purposes.
|
|
82
|
+
*/
|
|
83
|
+
storeKeyPair(kid: string, privateKey: object, publicKey: object, ttl: number): void | Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Retrieves the current private key used for signing.
|
|
86
|
+
*/
|
|
87
|
+
getPrivateKey(): Promise<object | undefined>;
|
|
88
|
+
/**
|
|
89
|
+
* Retrieves all valid public keys that have not expired.
|
|
90
|
+
* These are used for exposing in JWKS.
|
|
91
|
+
*/
|
|
92
|
+
getPublicKeys(): Promise<object[]>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Generates a new signing key pair and stores it in the associated {@link JwksKeyStore}.
|
|
96
|
+
* Used by {@link JwksRotator} to perform key rotation.
|
|
97
|
+
*/
|
|
98
|
+
export interface KeyGenerator {
|
|
99
|
+
/**
|
|
100
|
+
* Generates a new key pair and persists it to the key store.
|
|
101
|
+
*/
|
|
102
|
+
generateKeyPair(): Promise<void>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* An object capable of signing a JWT payload and returning the compact serialized token.
|
|
106
|
+
*
|
|
107
|
+
* Implement this interface to plug in a custom JWT signing strategy.
|
|
108
|
+
*/
|
|
109
|
+
export interface JwtSigner {
|
|
110
|
+
/**
|
|
111
|
+
* Signs the given payload as a JWT.
|
|
112
|
+
* @param payload - The JWT payload to sign.
|
|
113
|
+
* @returns An object containing the signed compact JWT string and the `kid` of the key used for signing.
|
|
114
|
+
*/
|
|
115
|
+
sign(payload: JWTPayload): Promise<{
|
|
116
|
+
token: string;
|
|
117
|
+
kid: string;
|
|
118
|
+
}>;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* An object capable of verifying a JWT and returning its typed payload.
|
|
122
|
+
*
|
|
123
|
+
* Implement this interface to plug in a custom JWT verification strategy
|
|
124
|
+
* (e.g. backed by a JWKS endpoint, a local key store, or a third-party library).
|
|
125
|
+
*/
|
|
126
|
+
export interface JwtVerifier {
|
|
127
|
+
/**
|
|
128
|
+
* Verifies the given JWT and returns its decoded payload.
|
|
129
|
+
*
|
|
130
|
+
* @template P - The expected shape of the JWT payload. Defaults to {@link JWTPayload}.
|
|
131
|
+
* @param token - The compact serialized JWT string to verify.
|
|
132
|
+
* @returns The verified and decoded payload.
|
|
133
|
+
* @throws If the token is invalid, expired, or cannot be verified.
|
|
134
|
+
*/
|
|
135
|
+
verify<P extends JWTPayload = JWTPayload>(token: string): Promise<P>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* A full JWT authority combining signing, verification, and JWKS key management.
|
|
139
|
+
*
|
|
140
|
+
* A `JwtAuthority` is responsible for:
|
|
141
|
+
* - Signing JWT payloads with the current private key ({@link JwtSigner.sign})
|
|
142
|
+
* - Verifying JWTs against the matching public key ({@link JwtVerifier.verify})
|
|
143
|
+
* - Exposing the JWKS (set of public keys) for external consumers
|
|
144
|
+
* - Generating new key pairs on demand or via a scheduled {@link JwksRotator}
|
|
145
|
+
*
|
|
146
|
+
* Use {@link JoseJwksAuthority} as the ready-made implementation backed by [jose](https://github.com/panva/jose).
|
|
147
|
+
*/
|
|
148
|
+
export interface JwtAuthority extends JwtVerifier, JwtSigner {
|
|
149
|
+
/**
|
|
150
|
+
* Retrieves all currently valid public keys from the key store.
|
|
151
|
+
* @returns An object whose `keys` array contains the public keys in JWK format.
|
|
152
|
+
*/
|
|
153
|
+
getPublicKeys(): Promise<{
|
|
154
|
+
keys: RawKey[];
|
|
155
|
+
}>;
|
|
156
|
+
/**
|
|
157
|
+
* Get current kid for observability/debugging
|
|
158
|
+
*/
|
|
159
|
+
getCurrentKid(): Promise<string | undefined>;
|
|
160
|
+
/**
|
|
161
|
+
* Helper for JWKS endpoint
|
|
162
|
+
*/
|
|
163
|
+
getJwksEndpointResponse(): Promise<{
|
|
164
|
+
keys: RawKey[];
|
|
165
|
+
}>;
|
|
166
|
+
/**
|
|
167
|
+
* Retrieves the public key corresponding to the given `kid` from the key store.
|
|
168
|
+
* @param kid - The key ID to look up.
|
|
169
|
+
* @returns The RSA public key if found, or `undefined` if not found or not an RSA key.
|
|
170
|
+
*/
|
|
171
|
+
getPublicKey(kid: string): Promise<RSA | undefined>;
|
|
172
|
+
/**
|
|
173
|
+
* Generates a new RSA key pair and stores it in the key store.
|
|
174
|
+
* The new key becomes the active signing key; the previous public key
|
|
175
|
+
* remains available in the JWKS until its TTL expires.
|
|
176
|
+
*/
|
|
177
|
+
generateKeyPair(): Promise<void>;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/esm/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@saurbit/oauth2-jwt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JWT utilities for @saurbit/oauth2 (jose-based)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"oauth2",
|
|
7
|
+
"jwt",
|
|
8
|
+
"jose",
|
|
9
|
+
"jwks",
|
|
10
|
+
"oidc"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/saurbit/saurbit.git"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"main": "./script/mod.js",
|
|
18
|
+
"module": "./esm/mod.js",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./esm/mod.js",
|
|
22
|
+
"require": "./script/mod.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"scripts": {},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"jose": "^6.2.2"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@saurbit/oauth2": "^0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"_generatedBy": "dnt@dev"
|
|
33
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { JWTPayload } from "jose";
|
|
2
|
+
import { JwksKeyStore, JwtAuthority, RawKey, RSA } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* JWT authority backed by [jose](https://github.com/panva/jose).
|
|
5
|
+
*
|
|
6
|
+
* Manages RS256 signing key pairs, signs and verifies JWTs, and returns the
|
|
7
|
+
* JWKS endpoint payload. Keys are stored in a {@link JwksKeyStore} and are
|
|
8
|
+
* generated automatically on first use.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { createInMemoryKeyStore, JoseJwksAuthority } from "@saurbit/oauth2-jwt";
|
|
13
|
+
*
|
|
14
|
+
* const store = createInMemoryKeyStore();
|
|
15
|
+
* const authority = new JoseJwksAuthority(store, 86400); // keys valid for 24 h
|
|
16
|
+
*
|
|
17
|
+
* const { token } = await authority.sign({ sub: "user-123", exp: Math.floor(Date.now() / 1000) + 3600 });
|
|
18
|
+
* const payload = await authority.verify(token);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class JoseJwksAuthority implements JwtAuthority {
|
|
22
|
+
#private;
|
|
23
|
+
/**
|
|
24
|
+
* @param store The key store used to manage JWKS keys.
|
|
25
|
+
* @param ttl Time-to-live for the keys in seconds.
|
|
26
|
+
*/
|
|
27
|
+
constructor(store: JwksKeyStore, ttl?: number);
|
|
28
|
+
/**
|
|
29
|
+
* Retrieves the current set of public keys from the key store.
|
|
30
|
+
* @returns An object containing the array of public keys.
|
|
31
|
+
*/
|
|
32
|
+
getPublicKeys(): Promise<{
|
|
33
|
+
keys: RawKey[];
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Get current kid for observability/debugging
|
|
37
|
+
*/
|
|
38
|
+
getCurrentKid(): Promise<string | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* Helps implement the JWKS endpoint by returning the current set of public keys in the expected format.
|
|
41
|
+
* @returns The current set of public keys in the JWKS format.
|
|
42
|
+
*/
|
|
43
|
+
getJwksEndpointResponse(): Promise<{
|
|
44
|
+
keys: RawKey[];
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Retrieves the public key corresponding to the given "kid" from the JWKS.
|
|
48
|
+
* @param kid The key ID of the desired public key.
|
|
49
|
+
* @returns The RSA public key if found, otherwise undefined.
|
|
50
|
+
*/
|
|
51
|
+
getPublicKey(kid: string): Promise<RSA | undefined>;
|
|
52
|
+
/**
|
|
53
|
+
* Generates a new RSA key pair, stores it in the key store with the appropriate metadata
|
|
54
|
+
* (kid, alg, use), and ensures that the public key is available for JWKS exposure.
|
|
55
|
+
*/
|
|
56
|
+
generateKeyPair(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Signs the given payload as a JWT using the current private key.
|
|
59
|
+
* The "kid" of the signing key is included in the JWT header to allow verifiers
|
|
60
|
+
* to select the correct public key from the JWKS for verification.
|
|
61
|
+
* This method ensures that the JWT is signed with a valid key and that
|
|
62
|
+
* the corresponding public key is available in the JWKS for future verification.
|
|
63
|
+
* @param payload The payload to be signed as a JWT.
|
|
64
|
+
* @returns An object containing the signed JWT and the key ID used for signing.
|
|
65
|
+
*/
|
|
66
|
+
sign(payload: JWTPayload): Promise<{
|
|
67
|
+
token: string;
|
|
68
|
+
kid: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Verifies the given JWT using the appropriate public key from the JWKS based on the "kid" in the JWT header.
|
|
72
|
+
* It performs additional checks to ensure the integrity and expected structure of the JWT,
|
|
73
|
+
* such as validating the algorithm and ensuring no unexpected JWK is present in the header.
|
|
74
|
+
* @param token
|
|
75
|
+
* @returns
|
|
76
|
+
*/
|
|
77
|
+
verify<P extends JWTPayload = JWTPayload>(token: string): Promise<P>;
|
|
78
|
+
/**
|
|
79
|
+
* Signs multiple payloads with the same private key, returning an array of tokens and their corresponding kids.
|
|
80
|
+
* This is useful for batch operations where multiple JWTs need to be issued at once,
|
|
81
|
+
* ensuring they all use the same key and can be verified against the same public key in the JWKS.
|
|
82
|
+
* @param payloads The array of payloads to be signed as JWTs.
|
|
83
|
+
* @returns An array of objects containing the signed JWTs and their corresponding key IDs.
|
|
84
|
+
*/
|
|
85
|
+
signMany(payloads: JWTPayload[]): Promise<{
|
|
86
|
+
token: string;
|
|
87
|
+
kid: string;
|
|
88
|
+
}[]>;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=jose_jwks_authority.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jose_jwks_authority.d.ts","sourceRoot":"","sources":["../src/jose_jwks_authority.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,UAAU,EAGX,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AA0BrE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAkB,YAAW,YAAY;;IAOpD;;;OAGG;gBACS,KAAK,EAAE,YAAY,EAAE,GAAG,GAAE,MAAc;IAsCpD;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IASlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKlD;;;OAGG;IACH,uBAAuB,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAItD;;;;OAIG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC;IAQzD;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;;;;;;;OAQG;IACG,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBxE;;;;;;OAMG;IACG,MAAM,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA+B1E;;;;;;OAMG;IACG,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAyBlF"}
|