@rudderjs/passport 1.0.0 → 1.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/dist/Passport.d.ts +93 -0
- package/dist/Passport.d.ts.map +1 -1
- package/dist/Passport.js +147 -0
- package/dist/Passport.js.map +1 -1
- package/dist/client-secret.d.ts +12 -0
- package/dist/client-secret.d.ts.map +1 -0
- package/dist/client-secret.js +63 -0
- package/dist/client-secret.js.map +1 -0
- package/dist/commands/client.d.ts +21 -0
- package/dist/commands/client.d.ts.map +1 -1
- package/dist/commands/client.js +27 -2
- package/dist/commands/client.js.map +1 -1
- package/dist/commands/keys.d.ts +28 -4
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +34 -4
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/purge.d.ts +6 -1
- package/dist/commands/purge.d.ts.map +1 -1
- package/dist/commands/purge.js +15 -31
- package/dist/commands/purge.js.map +1 -1
- package/dist/device-code-secret.d.ts +28 -0
- package/dist/device-code-secret.d.ts.map +1 -0
- package/dist/device-code-secret.js +31 -0
- package/dist/device-code-secret.js.map +1 -0
- package/dist/grants/authorization-code.d.ts +23 -0
- package/dist/grants/authorization-code.d.ts.map +1 -1
- package/dist/grants/authorization-code.js +126 -15
- package/dist/grants/authorization-code.js.map +1 -1
- package/dist/grants/client-credentials.d.ts.map +1 -1
- package/dist/grants/client-credentials.js +13 -5
- package/dist/grants/client-credentials.js.map +1 -1
- package/dist/grants/device-code.d.ts +10 -1
- package/dist/grants/device-code.d.ts.map +1 -1
- package/dist/grants/device-code.js +41 -10
- package/dist/grants/device-code.js.map +1 -1
- package/dist/grants/index.d.ts +1 -1
- package/dist/grants/index.d.ts.map +1 -1
- package/dist/grants/index.js +1 -1
- package/dist/grants/index.js.map +1 -1
- package/dist/grants/issue-tokens.d.ts +9 -0
- package/dist/grants/issue-tokens.d.ts.map +1 -1
- package/dist/grants/issue-tokens.js +39 -5
- package/dist/grants/issue-tokens.js.map +1 -1
- package/dist/grants/refresh-token.d.ts.map +1 -1
- package/dist/grants/refresh-token.js +64 -9
- package/dist/grants/refresh-token.js.map +1 -1
- package/dist/grants/safe-compare.d.ts +19 -0
- package/dist/grants/safe-compare.d.ts.map +1 -0
- package/dist/grants/safe-compare.js +28 -0
- package/dist/grants/safe-compare.js.map +1 -0
- package/dist/index.d.ts +27 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -67
- package/dist/index.js.map +1 -1
- package/dist/middleware/bearer.d.ts.map +1 -1
- package/dist/middleware/bearer.js +36 -6
- package/dist/middleware/bearer.js.map +1 -1
- package/dist/middleware/scope.d.ts +12 -2
- package/dist/middleware/scope.d.ts.map +1 -1
- package/dist/middleware/scope.js +46 -2
- package/dist/middleware/scope.js.map +1 -1
- package/dist/models/AccessToken.d.ts +32 -0
- package/dist/models/AccessToken.d.ts.map +1 -1
- package/dist/models/AccessToken.js +63 -3
- package/dist/models/AccessToken.js.map +1 -1
- package/dist/models/AuthCode.d.ts +16 -0
- package/dist/models/AuthCode.d.ts.map +1 -1
- package/dist/models/AuthCode.js +17 -1
- package/dist/models/AuthCode.js.map +1 -1
- package/dist/models/DeviceCode.d.ts +12 -2
- package/dist/models/DeviceCode.d.ts.map +1 -1
- package/dist/models/DeviceCode.js +7 -1
- package/dist/models/DeviceCode.js.map +1 -1
- package/dist/models/OAuthClient.d.ts +4 -0
- package/dist/models/OAuthClient.d.ts.map +1 -1
- package/dist/models/OAuthClient.js +13 -1
- package/dist/models/OAuthClient.js.map +1 -1
- package/dist/models/RefreshToken.d.ts +11 -0
- package/dist/models/RefreshToken.d.ts.map +1 -1
- package/dist/models/RefreshToken.js +12 -2
- package/dist/models/RefreshToken.js.map +1 -1
- package/dist/models/helpers.d.ts +6 -0
- package/dist/models/helpers.d.ts.map +1 -1
- package/dist/models/helpers.js +15 -2
- package/dist/models/helpers.js.map +1 -1
- package/dist/opaque-token.d.ts +32 -0
- package/dist/opaque-token.d.ts.map +1 -0
- package/dist/opaque-token.js +38 -0
- package/dist/opaque-token.js.map +1 -0
- package/dist/personal-access-tokens.d.ts.map +1 -1
- package/dist/personal-access-tokens.js +48 -10
- package/dist/personal-access-tokens.js.map +1 -1
- package/dist/routes.d.ts +149 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +279 -41
- package/dist/routes.js.map +1 -1
- package/dist/token.d.ts +80 -4
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +97 -13
- package/dist/token.js.map +1 -1
- package/package.json +5 -5
- package/schema/passport.prisma +29 -9
package/dist/Passport.d.ts
CHANGED
|
@@ -28,6 +28,16 @@ export declare class Passport {
|
|
|
28
28
|
private static _keyPath;
|
|
29
29
|
private static _privateKey;
|
|
30
30
|
private static _publicKey;
|
|
31
|
+
/**
|
|
32
|
+
* Previous public key, retained for verification only after a `passport:keys
|
|
33
|
+
* --force` rotation. Tokens minted before the rotation keep verifying via
|
|
34
|
+
* this slot during the grace window; new tokens are signed by the current
|
|
35
|
+
* private key. Single-slot — one rotation deep — by design (operators who
|
|
36
|
+
* need a longer history should stage rotations to land outside the
|
|
37
|
+
* configured access-token lifetime). See JWKS verifier design notes in
|
|
38
|
+
* `verificationKeys()` below.
|
|
39
|
+
*/
|
|
40
|
+
private static _previousPublicKey;
|
|
31
41
|
private static _clientModel;
|
|
32
42
|
private static _tokenModel;
|
|
33
43
|
private static _refreshTokenModel;
|
|
@@ -35,6 +45,16 @@ export declare class Passport {
|
|
|
35
45
|
private static _deviceCodeModel;
|
|
36
46
|
private static _authorizationView;
|
|
37
47
|
private static _routesIgnored;
|
|
48
|
+
private static _issuer;
|
|
49
|
+
/**
|
|
50
|
+
* Maximum value (in seconds) the per-row `oauth_device_codes.interval` is
|
|
51
|
+
* allowed to grow to via repeated `slow_down` escalations (RFC 8628 §3.5
|
|
52
|
+
* doesn't specify a cap; we add one to keep degenerate clients from
|
|
53
|
+
* pushing the interval to absurd values). 60 seconds is the default — long
|
|
54
|
+
* enough to make a misbehaving client back off meaningfully, short enough
|
|
55
|
+
* that a legitimate user typing the user_code never hits it.
|
|
56
|
+
*/
|
|
57
|
+
private static _deviceMaxInterval;
|
|
38
58
|
/** Define available OAuth scopes. */
|
|
39
59
|
static tokensCan(scopes: Record<string, string>): void;
|
|
40
60
|
/** Check if a scope is defined. */
|
|
@@ -55,11 +75,53 @@ export declare class Passport {
|
|
|
55
75
|
static keyPath(): string;
|
|
56
76
|
/** Set keys directly (from environment variables). */
|
|
57
77
|
static setKeys(privateKey: string, publicKey: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Stamp the previous public key for verification grace after a key
|
|
80
|
+
* rotation. Tokens carrying `kid` for this key — or any token whose
|
|
81
|
+
* signature happens to verify against it — keep working until they
|
|
82
|
+
* naturally expire. Pair with the env var `PASSPORT_PREVIOUS_PUBLIC_KEY`
|
|
83
|
+
* if you don't want to rely on the on-disk `oauth-previous-public.key`
|
|
84
|
+
* convention. Pass `null` to clear.
|
|
85
|
+
*/
|
|
86
|
+
static setPreviousPublicKey(publicKey: string | null): void;
|
|
87
|
+
/**
|
|
88
|
+
* Probe whether an RSA keypair is reachable — either explicitly set via
|
|
89
|
+
* `setKeys()` (env vars) or readable on disk under the configured key path.
|
|
90
|
+
* Used by `PassportProvider.boot()` to surface a startup warning when keys
|
|
91
|
+
* are missing, before the first `/oauth/*` request fails with a confusing
|
|
92
|
+
* file-not-found error.
|
|
93
|
+
*
|
|
94
|
+
* Does NOT load or cache the keys; it only stats the files.
|
|
95
|
+
*/
|
|
96
|
+
static keysAvailable(): Promise<boolean>;
|
|
58
97
|
/** Load keys from files or env. Returns { privateKey, publicKey }. */
|
|
59
98
|
static keys(): Promise<{
|
|
60
99
|
privateKey: string;
|
|
61
100
|
publicKey: string;
|
|
62
101
|
}>;
|
|
102
|
+
/**
|
|
103
|
+
* All public keys that should be considered for JWT signature verification,
|
|
104
|
+
* ordered current-first. After `passport:keys --force` rotates the
|
|
105
|
+
* keypair, the previous public key lingers in this list (loaded from
|
|
106
|
+
* `oauth-previous-public.key` on disk or set via `setPreviousPublicKey()`)
|
|
107
|
+
* so JWTs signed before the rotation keep verifying during their natural
|
|
108
|
+
* lifetime — `verifyToken()` walks the list and accepts a match against
|
|
109
|
+
* any entry. Without this, every rotation forced an immediate global
|
|
110
|
+
* sign-out.
|
|
111
|
+
*
|
|
112
|
+
* Tokens minted by recent versions also carry a `kid` JWT header equal to
|
|
113
|
+
* the SHA-256 of the public key that signed them, so the verifier can
|
|
114
|
+
* pick the right key directly without trial-and-error. Legacy tokens with
|
|
115
|
+
* no `kid` fall through to "try each in order".
|
|
116
|
+
*
|
|
117
|
+
* Single previous-slot is intentional: one rotation deep. Operators who
|
|
118
|
+
* need a multi-step grace should stage rotations to land outside the
|
|
119
|
+
* configured access-token lifetime — at that point old tokens have
|
|
120
|
+
* expired anyway and a longer history buys nothing.
|
|
121
|
+
*/
|
|
122
|
+
static verificationKeys(): Promise<string[]>;
|
|
123
|
+
/** Get the configured previous public key, if any. */
|
|
124
|
+
static previousPublicKey(): string | null;
|
|
63
125
|
static useClientModel(cls: typeof OAuthClient): void;
|
|
64
126
|
static useTokenModel(cls: typeof AccessToken): void;
|
|
65
127
|
static useRefreshTokenModel(cls: typeof RefreshToken): void;
|
|
@@ -83,6 +145,37 @@ export declare class Passport {
|
|
|
83
145
|
*/
|
|
84
146
|
static ignoreRoutes(): void;
|
|
85
147
|
static routesIgnored(): boolean;
|
|
148
|
+
/**
|
|
149
|
+
* Configure the JWT `iss` claim that `createToken()` stamps on every new
|
|
150
|
+
* access token, and that `verifyToken()` validates when called with
|
|
151
|
+
* `expectedIssuer: Passport.issuer()` (BearerMiddleware does this
|
|
152
|
+
* automatically). Typically set to the canonical app URL — e.g.
|
|
153
|
+
* `Passport.useIssuer('https://app.example.com')`.
|
|
154
|
+
*
|
|
155
|
+
* RFC 8725 §3.10 recommends issuer validation once a deployment has more
|
|
156
|
+
* than one possible signer (multi-tenant, staging+prod sharing keys, etc.).
|
|
157
|
+
* Tokens minted before this is configured carry no `iss` claim and are
|
|
158
|
+
* exempt during the migration window — same pattern as redirect_uri (P1)
|
|
159
|
+
* and familyId (P4).
|
|
160
|
+
*/
|
|
161
|
+
static useIssuer(url: string): void;
|
|
162
|
+
static issuer(): string | null;
|
|
163
|
+
/**
|
|
164
|
+
* Configure the maximum value (in seconds) the per-row device-code
|
|
165
|
+
* polling interval is allowed to grow to via repeated `slow_down`
|
|
166
|
+
* escalations. Must be >= 5 (the initial interval) and >= the increment
|
|
167
|
+
* step (5s) to make sense; values smaller than that disable escalation
|
|
168
|
+
* entirely and are clamped at 5.
|
|
169
|
+
*
|
|
170
|
+
* Defaults to 60 seconds. Raise it for niche flows where a misbehaving
|
|
171
|
+
* client should be backed off more aggressively (e.g. a daemon polling
|
|
172
|
+
* with no human in the loop). Lower it if your device-flow consumers can
|
|
173
|
+
* tolerate a quicker authorization handshake — but lowering below ~30
|
|
174
|
+
* gives legitimate users a small window to enter the user_code.
|
|
175
|
+
*/
|
|
176
|
+
static deviceMaxInterval(seconds: number): void;
|
|
177
|
+
/** Current cap on `oauth_device_codes.interval` (seconds). */
|
|
178
|
+
static deviceMaxIntervalSeconds(): number;
|
|
86
179
|
/** @internal */
|
|
87
180
|
static reset(): void;
|
|
88
181
|
}
|
package/dist/Passport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Passport.d.ts","sourceRoot":"","sources":["../src/Passport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAO,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAO,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAU,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAQ,wBAAwB,CAAA;AAI1D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAW,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,wBAAwB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;AAE/F,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAC,OAAO,CAA4B;IAClD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAiC;IAC9D,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAA2B;IAC/D,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAA+B;IACpE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAsB;IAChD,OAAO,CAAC,MAAM,CAAC,UAAU,CAAsB;
|
|
1
|
+
{"version":3,"file":"Passport.d.ts","sourceRoot":"","sources":["../src/Passport.ts"],"names":[],"mappings":"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"}
|
package/dist/Passport.js
CHANGED
|
@@ -6,6 +6,16 @@ export class Passport {
|
|
|
6
6
|
static _keyPath = 'storage';
|
|
7
7
|
static _privateKey = null;
|
|
8
8
|
static _publicKey = null;
|
|
9
|
+
/**
|
|
10
|
+
* Previous public key, retained for verification only after a `passport:keys
|
|
11
|
+
* --force` rotation. Tokens minted before the rotation keep verifying via
|
|
12
|
+
* this slot during the grace window; new tokens are signed by the current
|
|
13
|
+
* private key. Single-slot — one rotation deep — by design (operators who
|
|
14
|
+
* need a longer history should stage rotations to land outside the
|
|
15
|
+
* configured access-token lifetime). See JWKS verifier design notes in
|
|
16
|
+
* `verificationKeys()` below.
|
|
17
|
+
*/
|
|
18
|
+
static _previousPublicKey = null;
|
|
9
19
|
// Custom model overrides (lazy — resolved at use-site so the defaults aren't eagerly loaded).
|
|
10
20
|
static _clientModel = null;
|
|
11
21
|
static _tokenModel = null;
|
|
@@ -16,6 +26,20 @@ export class Passport {
|
|
|
16
26
|
static _authorizationView = null;
|
|
17
27
|
// Route auto-registration toggle
|
|
18
28
|
static _routesIgnored = false;
|
|
29
|
+
// JWT issuer URL — when set, createToken stamps `iss` on the payload and
|
|
30
|
+
// verifyToken can validate it via `expectedIssuer`. Optional per RFC 7519
|
|
31
|
+
// but recommended by RFC 8725 §3.10 once the deployment has more than one
|
|
32
|
+
// possible issuer (e.g. multi-tenant or staging vs prod sharing keys).
|
|
33
|
+
static _issuer = null;
|
|
34
|
+
/**
|
|
35
|
+
* Maximum value (in seconds) the per-row `oauth_device_codes.interval` is
|
|
36
|
+
* allowed to grow to via repeated `slow_down` escalations (RFC 8628 §3.5
|
|
37
|
+
* doesn't specify a cap; we add one to keep degenerate clients from
|
|
38
|
+
* pushing the interval to absurd values). 60 seconds is the default — long
|
|
39
|
+
* enough to make a misbehaving client back off meaningfully, short enough
|
|
40
|
+
* that a legitimate user typing the user_code never hits it.
|
|
41
|
+
*/
|
|
42
|
+
static _deviceMaxInterval = 60;
|
|
19
43
|
// ── Scopes ──────────────────────────────────────────────
|
|
20
44
|
/** Define available OAuth scopes. */
|
|
21
45
|
static tokensCan(scopes) {
|
|
@@ -52,6 +76,39 @@ export class Passport {
|
|
|
52
76
|
this._privateKey = privateKey;
|
|
53
77
|
this._publicKey = publicKey;
|
|
54
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Stamp the previous public key for verification grace after a key
|
|
81
|
+
* rotation. Tokens carrying `kid` for this key — or any token whose
|
|
82
|
+
* signature happens to verify against it — keep working until they
|
|
83
|
+
* naturally expire. Pair with the env var `PASSPORT_PREVIOUS_PUBLIC_KEY`
|
|
84
|
+
* if you don't want to rely on the on-disk `oauth-previous-public.key`
|
|
85
|
+
* convention. Pass `null` to clear.
|
|
86
|
+
*/
|
|
87
|
+
static setPreviousPublicKey(publicKey) {
|
|
88
|
+
this._previousPublicKey = publicKey && publicKey.length > 0 ? publicKey : null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Probe whether an RSA keypair is reachable — either explicitly set via
|
|
92
|
+
* `setKeys()` (env vars) or readable on disk under the configured key path.
|
|
93
|
+
* Used by `PassportProvider.boot()` to surface a startup warning when keys
|
|
94
|
+
* are missing, before the first `/oauth/*` request fails with a confusing
|
|
95
|
+
* file-not-found error.
|
|
96
|
+
*
|
|
97
|
+
* Does NOT load or cache the keys; it only stats the files.
|
|
98
|
+
*/
|
|
99
|
+
static async keysAvailable() {
|
|
100
|
+
if (this._privateKey && this._publicKey)
|
|
101
|
+
return true;
|
|
102
|
+
const { stat } = await import('node:fs/promises');
|
|
103
|
+
const { join } = await import('node:path');
|
|
104
|
+
const privatePath = join(process.cwd(), this._keyPath, 'oauth-private.key');
|
|
105
|
+
const publicPath = join(process.cwd(), this._keyPath, 'oauth-public.key');
|
|
106
|
+
const [priv, pub] = await Promise.all([
|
|
107
|
+
stat(privatePath).then(() => true, () => false),
|
|
108
|
+
stat(publicPath).then(() => true, () => false),
|
|
109
|
+
]);
|
|
110
|
+
return priv && pub;
|
|
111
|
+
}
|
|
55
112
|
/** Load keys from files or env. Returns { privateKey, publicKey }. */
|
|
56
113
|
static async keys() {
|
|
57
114
|
// Prefer explicitly set keys (from env vars)
|
|
@@ -71,6 +128,54 @@ export class Passport {
|
|
|
71
128
|
this._publicKey = publicKey;
|
|
72
129
|
return { privateKey, publicKey };
|
|
73
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* All public keys that should be considered for JWT signature verification,
|
|
133
|
+
* ordered current-first. After `passport:keys --force` rotates the
|
|
134
|
+
* keypair, the previous public key lingers in this list (loaded from
|
|
135
|
+
* `oauth-previous-public.key` on disk or set via `setPreviousPublicKey()`)
|
|
136
|
+
* so JWTs signed before the rotation keep verifying during their natural
|
|
137
|
+
* lifetime — `verifyToken()` walks the list and accepts a match against
|
|
138
|
+
* any entry. Without this, every rotation forced an immediate global
|
|
139
|
+
* sign-out.
|
|
140
|
+
*
|
|
141
|
+
* Tokens minted by recent versions also carry a `kid` JWT header equal to
|
|
142
|
+
* the SHA-256 of the public key that signed them, so the verifier can
|
|
143
|
+
* pick the right key directly without trial-and-error. Legacy tokens with
|
|
144
|
+
* no `kid` fall through to "try each in order".
|
|
145
|
+
*
|
|
146
|
+
* Single previous-slot is intentional: one rotation deep. Operators who
|
|
147
|
+
* need a multi-step grace should stage rotations to land outside the
|
|
148
|
+
* configured access-token lifetime — at that point old tokens have
|
|
149
|
+
* expired anyway and a longer history buys nothing.
|
|
150
|
+
*/
|
|
151
|
+
static async verificationKeys() {
|
|
152
|
+
const { publicKey } = await this.keys();
|
|
153
|
+
const keys = [publicKey];
|
|
154
|
+
if (this._previousPublicKey) {
|
|
155
|
+
keys.push(this._previousPublicKey);
|
|
156
|
+
return keys;
|
|
157
|
+
}
|
|
158
|
+
// Filesystem fallback — `oauth-previous-public.key` is written by
|
|
159
|
+
// `generateKeys({ force: true })` during a rotation, alongside the
|
|
160
|
+
// timestamped audit backup.
|
|
161
|
+
const { readFile } = await import('node:fs/promises');
|
|
162
|
+
const { join } = await import('node:path');
|
|
163
|
+
const previousPath = join(process.cwd(), this._keyPath, 'oauth-previous-public.key');
|
|
164
|
+
try {
|
|
165
|
+
const previous = await readFile(previousPath, 'utf8');
|
|
166
|
+
this._previousPublicKey = previous;
|
|
167
|
+
keys.push(previous);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// No previous key on disk — first rotation hasn't happened yet, or
|
|
171
|
+
// the operator deleted the file to drop the grace window.
|
|
172
|
+
}
|
|
173
|
+
return keys;
|
|
174
|
+
}
|
|
175
|
+
/** Get the configured previous public key, if any. */
|
|
176
|
+
static previousPublicKey() {
|
|
177
|
+
return this._previousPublicKey;
|
|
178
|
+
}
|
|
74
179
|
// ── Custom Models ───────────────────────────────────────
|
|
75
180
|
static useClientModel(cls) { this._clientModel = cls; }
|
|
76
181
|
static useTokenModel(cls) { this._tokenModel = cls; }
|
|
@@ -125,6 +230,45 @@ export class Passport {
|
|
|
125
230
|
static routesIgnored() {
|
|
126
231
|
return this._routesIgnored;
|
|
127
232
|
}
|
|
233
|
+
// ── JWT issuer ──────────────────────────────────────────
|
|
234
|
+
/**
|
|
235
|
+
* Configure the JWT `iss` claim that `createToken()` stamps on every new
|
|
236
|
+
* access token, and that `verifyToken()` validates when called with
|
|
237
|
+
* `expectedIssuer: Passport.issuer()` (BearerMiddleware does this
|
|
238
|
+
* automatically). Typically set to the canonical app URL — e.g.
|
|
239
|
+
* `Passport.useIssuer('https://app.example.com')`.
|
|
240
|
+
*
|
|
241
|
+
* RFC 8725 §3.10 recommends issuer validation once a deployment has more
|
|
242
|
+
* than one possible signer (multi-tenant, staging+prod sharing keys, etc.).
|
|
243
|
+
* Tokens minted before this is configured carry no `iss` claim and are
|
|
244
|
+
* exempt during the migration window — same pattern as redirect_uri (P1)
|
|
245
|
+
* and familyId (P4).
|
|
246
|
+
*/
|
|
247
|
+
static useIssuer(url) { this._issuer = url || null; }
|
|
248
|
+
static issuer() { return this._issuer; }
|
|
249
|
+
// ── Device flow polling cap (RFC 8628 §3.5) ─────────────
|
|
250
|
+
/**
|
|
251
|
+
* Configure the maximum value (in seconds) the per-row device-code
|
|
252
|
+
* polling interval is allowed to grow to via repeated `slow_down`
|
|
253
|
+
* escalations. Must be >= 5 (the initial interval) and >= the increment
|
|
254
|
+
* step (5s) to make sense; values smaller than that disable escalation
|
|
255
|
+
* entirely and are clamped at 5.
|
|
256
|
+
*
|
|
257
|
+
* Defaults to 60 seconds. Raise it for niche flows where a misbehaving
|
|
258
|
+
* client should be backed off more aggressively (e.g. a daemon polling
|
|
259
|
+
* with no human in the loop). Lower it if your device-flow consumers can
|
|
260
|
+
* tolerate a quicker authorization handshake — but lowering below ~30
|
|
261
|
+
* gives legitimate users a small window to enter the user_code.
|
|
262
|
+
*/
|
|
263
|
+
static deviceMaxInterval(seconds) {
|
|
264
|
+
// Never below the floor — escalation is by 5s, so a cap below 5
|
|
265
|
+
// would prevent any escalation from ever taking effect.
|
|
266
|
+
this._deviceMaxInterval = Math.max(5, Math.floor(seconds));
|
|
267
|
+
}
|
|
268
|
+
/** Current cap on `oauth_device_codes.interval` (seconds). */
|
|
269
|
+
static deviceMaxIntervalSeconds() {
|
|
270
|
+
return this._deviceMaxInterval;
|
|
271
|
+
}
|
|
128
272
|
// ── Reset (testing) ─────────────────────────────────────
|
|
129
273
|
/** @internal */
|
|
130
274
|
static reset() {
|
|
@@ -135,6 +279,7 @@ export class Passport {
|
|
|
135
279
|
this._keyPath = 'storage';
|
|
136
280
|
this._privateKey = null;
|
|
137
281
|
this._publicKey = null;
|
|
282
|
+
this._previousPublicKey = null;
|
|
138
283
|
this._clientModel = null;
|
|
139
284
|
this._tokenModel = null;
|
|
140
285
|
this._refreshTokenModel = null;
|
|
@@ -142,6 +287,8 @@ export class Passport {
|
|
|
142
287
|
this._deviceCodeModel = null;
|
|
143
288
|
this._authorizationView = null;
|
|
144
289
|
this._routesIgnored = false;
|
|
290
|
+
this._issuer = null;
|
|
291
|
+
this._deviceMaxInterval = 60;
|
|
145
292
|
}
|
|
146
293
|
}
|
|
147
294
|
//# sourceMappingURL=Passport.js.map
|
package/dist/Passport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Passport.js","sourceRoot":"","sources":["../src/Passport.ts"],"names":[],"mappings":"AAyBA,MAAM,OAAO,QAAQ;IACX,MAAM,CAAC,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC1C,MAAM,CAAC,cAAc,GAAS,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAG,UAAU;IACnE,MAAM,CAAC,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAE,UAAU;IACnE,MAAM,CAAC,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,YAAY;IACzE,MAAM,CAAC,QAAQ,GAAG,SAAS,CAAA;IAC3B,MAAM,CAAC,WAAW,GAAkB,IAAI,CAAA;IACxC,MAAM,CAAC,UAAU,GAAkB,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"Passport.js","sourceRoot":"","sources":["../src/Passport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash a plain-text client secret for storage. Returns a peppered HMAC if
|
|
3
|
+
* `APP_KEY` is set, otherwise a plain SHA-256 hex digest.
|
|
4
|
+
*/
|
|
5
|
+
export declare function hashClientSecret(plainSecret: string): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Verify a plain-text client secret against a stored hash. Constant-time;
|
|
8
|
+
* format is auto-detected from the stored value's prefix so legacy plain
|
|
9
|
+
* SHA-256 rows continue to verify after `APP_KEY` is configured.
|
|
10
|
+
*/
|
|
11
|
+
export declare function verifyClientSecret(plainSecret: string, stored: string | null | undefined): Promise<boolean>;
|
|
12
|
+
//# sourceMappingURL=client-secret.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-secret.d.ts","sourceRoot":"","sources":["../src/client-secret.ts"],"names":[],"mappings":"AAkCA;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ3E;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,OAAO,CAAC,OAAO,CAAC,CAclB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { safeCompare } from './grants/safe-compare.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hashing + verification of OAuth client secrets at rest.
|
|
4
|
+
*
|
|
5
|
+
* Two storage formats are supported:
|
|
6
|
+
*
|
|
7
|
+
* - **Peppered** — `peppered:<HMAC-SHA256(secret, APP_KEY)>` (hex). Used
|
|
8
|
+
* when `APP_KEY` is set at the time the client is created. A leaked DB
|
|
9
|
+
* dump alone cannot be used to verify candidate secrets without also
|
|
10
|
+
* knowing `APP_KEY`.
|
|
11
|
+
* - **Plain SHA-256** — bare 64-char hex digest. Used when `APP_KEY` is
|
|
12
|
+
* unset. This matches the historical (pre-2026-05) format and is what
|
|
13
|
+
* Laravel Passport stores; client secrets are 256-bit CSPRNG so the
|
|
14
|
+
* hash adds little cryptographic protection beyond defense-in-depth.
|
|
15
|
+
*
|
|
16
|
+
* The format is self-describing via the `peppered:` prefix, so existing
|
|
17
|
+
* rows minted before this change keep verifying against their plain
|
|
18
|
+
* SHA-256 hashes — there is no migration step. New rows use whichever
|
|
19
|
+
* format is available at creation time.
|
|
20
|
+
*
|
|
21
|
+
* Rotating `APP_KEY` invalidates every peppered client secret, the same
|
|
22
|
+
* way rotating the RSA keypair invalidates every live access token. The
|
|
23
|
+
* fallback path is to re-issue secrets via `passport:client` after the
|
|
24
|
+
* rotation; legacy plain-SHA-256 rows are unaffected.
|
|
25
|
+
*/
|
|
26
|
+
const PEPPERED_PREFIX = 'peppered:';
|
|
27
|
+
function appKey() {
|
|
28
|
+
const key = process.env['APP_KEY'];
|
|
29
|
+
return key && key.length > 0 ? key : null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Hash a plain-text client secret for storage. Returns a peppered HMAC if
|
|
33
|
+
* `APP_KEY` is set, otherwise a plain SHA-256 hex digest.
|
|
34
|
+
*/
|
|
35
|
+
export async function hashClientSecret(plainSecret) {
|
|
36
|
+
const { createHash, createHmac } = await import('node:crypto');
|
|
37
|
+
const pepper = appKey();
|
|
38
|
+
if (pepper) {
|
|
39
|
+
const mac = createHmac('sha256', pepper).update(plainSecret).digest('hex');
|
|
40
|
+
return `${PEPPERED_PREFIX}${mac}`;
|
|
41
|
+
}
|
|
42
|
+
return createHash('sha256').update(plainSecret).digest('hex');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Verify a plain-text client secret against a stored hash. Constant-time;
|
|
46
|
+
* format is auto-detected from the stored value's prefix so legacy plain
|
|
47
|
+
* SHA-256 rows continue to verify after `APP_KEY` is configured.
|
|
48
|
+
*/
|
|
49
|
+
export async function verifyClientSecret(plainSecret, stored) {
|
|
50
|
+
if (!stored)
|
|
51
|
+
return false;
|
|
52
|
+
const { createHash, createHmac } = await import('node:crypto');
|
|
53
|
+
if (stored.startsWith(PEPPERED_PREFIX)) {
|
|
54
|
+
const pepper = appKey();
|
|
55
|
+
if (!pepper)
|
|
56
|
+
return false;
|
|
57
|
+
const mac = createHmac('sha256', pepper).update(plainSecret).digest('hex');
|
|
58
|
+
return safeCompare(mac, stored.slice(PEPPERED_PREFIX.length));
|
|
59
|
+
}
|
|
60
|
+
const hashed = createHash('sha256').update(plainSecret).digest('hex');
|
|
61
|
+
return safeCompare(hashed, stored);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=client-secret.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-secret.js","sourceRoot":"","sources":["../src/client-secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,eAAe,GAAG,WAAW,CAAA;AAEnC,SAAS,MAAM;IACb,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAClC,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACxD,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAA;IACvB,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC1E,OAAO,GAAG,eAAe,GAAG,GAAG,EAAE,CAAA;IACnC,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,MAAiC;IAEjC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAEzB,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAE9D,IAAI,MAAM,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAA;QACvB,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAA;QACzB,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC1E,OAAO,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAA;IAC/D,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACrE,OAAO,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AACpC,CAAC"}
|
|
@@ -5,6 +5,27 @@ export interface CreateClientOpts {
|
|
|
5
5
|
grantTypes?: string[];
|
|
6
6
|
confidential?: boolean;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the grant-types array for a `passport:client` invocation, given
|
|
10
|
+
* the parsed CLI flags. Pure — exported so the CLI handler stays a thin
|
|
11
|
+
* wrapper and the flag → array mapping is unit-testable.
|
|
12
|
+
*
|
|
13
|
+
* - `--device` → `['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token']`
|
|
14
|
+
* (RFC 8628 doesn't mandate a fixed grant list; pairing `refresh_token`
|
|
15
|
+
* with the device flow is the expected default — without it, the
|
|
16
|
+
* tokens minted by polling can't be refreshed.)
|
|
17
|
+
* - `--client-credentials` → `['client_credentials']`
|
|
18
|
+
* - default → `['authorization_code', 'refresh_token']`
|
|
19
|
+
*
|
|
20
|
+
* `--personal` is intentionally NOT a case here — personal access tokens
|
|
21
|
+
* don't need a CLI-created OAuth client. `passport:client` short-circuits
|
|
22
|
+
* before this resolver runs and prints a hint pointing at
|
|
23
|
+
* `HasApiTokens.createToken()` instead.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveClientGrantTypes(flags: {
|
|
26
|
+
isDevice?: boolean;
|
|
27
|
+
isM2M?: boolean;
|
|
28
|
+
}): string[];
|
|
8
29
|
/**
|
|
9
30
|
* Create an OAuth client programmatically.
|
|
10
31
|
* Returns the client and the plain-text secret (if confidential).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/commands/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/commands/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAU,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAG,MAAM,EAAE,CAAA;IACtB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CAIhG;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAClE,MAAM,EAAE,WAAW,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB,CAAC,CAuBD"}
|
package/dist/commands/client.js
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import { Passport } from '../Passport.js';
|
|
2
|
+
import { hashClientSecret } from '../client-secret.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the grant-types array for a `passport:client` invocation, given
|
|
5
|
+
* the parsed CLI flags. Pure — exported so the CLI handler stays a thin
|
|
6
|
+
* wrapper and the flag → array mapping is unit-testable.
|
|
7
|
+
*
|
|
8
|
+
* - `--device` → `['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token']`
|
|
9
|
+
* (RFC 8628 doesn't mandate a fixed grant list; pairing `refresh_token`
|
|
10
|
+
* with the device flow is the expected default — without it, the
|
|
11
|
+
* tokens minted by polling can't be refreshed.)
|
|
12
|
+
* - `--client-credentials` → `['client_credentials']`
|
|
13
|
+
* - default → `['authorization_code', 'refresh_token']`
|
|
14
|
+
*
|
|
15
|
+
* `--personal` is intentionally NOT a case here — personal access tokens
|
|
16
|
+
* don't need a CLI-created OAuth client. `passport:client` short-circuits
|
|
17
|
+
* before this resolver runs and prints a hint pointing at
|
|
18
|
+
* `HasApiTokens.createToken()` instead.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveClientGrantTypes(flags) {
|
|
21
|
+
if (flags.isDevice)
|
|
22
|
+
return ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token'];
|
|
23
|
+
if (flags.isM2M)
|
|
24
|
+
return ['client_credentials'];
|
|
25
|
+
return ['authorization_code', 'refresh_token'];
|
|
26
|
+
}
|
|
2
27
|
/**
|
|
3
28
|
* Create an OAuth client programmatically.
|
|
4
29
|
* Returns the client and the plain-text secret (if confidential).
|
|
5
30
|
*/
|
|
6
31
|
export async function createClient(opts) {
|
|
7
|
-
const { randomBytes
|
|
32
|
+
const { randomBytes } = await import('node:crypto');
|
|
8
33
|
const confidential = opts.confidential ?? true;
|
|
9
34
|
let plainSecret = null;
|
|
10
35
|
let hashedSecret = null;
|
|
11
36
|
if (confidential) {
|
|
12
37
|
plainSecret = randomBytes(32).toString('hex');
|
|
13
|
-
hashedSecret =
|
|
38
|
+
hashedSecret = await hashClientSecret(plainSecret);
|
|
14
39
|
}
|
|
15
40
|
const ClientCls = await Passport.clientModel();
|
|
16
41
|
const client = await ClientCls.create({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/commands/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/commands/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAUtD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAA8C;IACpF,IAAI,KAAK,CAAC,QAAQ;QAAE,OAAO,CAAC,8CAA8C,EAAE,eAAe,CAAC,CAAA;IAC5F,IAAI,KAAK,CAAC,KAAK;QAAK,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACjD,OAAO,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAA;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAsB;IAIvD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAEnD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAA;IAC9C,IAAI,WAAW,GAAkB,IAAI,CAAA;IACrC,IAAI,YAAY,GAAkB,IAAI,CAAA;IAEtC,IAAI,YAAY,EAAE,CAAC;QACjB,WAAW,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC7C,YAAY,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACpD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAA;IAC9C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC;QACpC,IAAI,EAAU,IAAI,CAAC,IAAI;QACvB,MAAM,EAAQ,YAAY;QAC1B,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,UAAU,EAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACvE,MAAM,EAAQ,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,YAAY;KACc,CAAgB,CAAA;IAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;AACxC,CAAC"}
|
package/dist/commands/keys.d.ts
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
|
+
export interface GenerateKeysResult {
|
|
2
|
+
privatePath: string;
|
|
3
|
+
publicPath: string;
|
|
4
|
+
/** Backup paths if existing keys were rotated under --force; null otherwise. */
|
|
5
|
+
backup: {
|
|
6
|
+
privatePath: string;
|
|
7
|
+
publicPath: string;
|
|
8
|
+
} | null;
|
|
9
|
+
/**
|
|
10
|
+
* Path of the rolling "previous public key" written under --force. The
|
|
11
|
+
* verifier (Passport.verificationKeys()) picks this up automatically, so
|
|
12
|
+
* JWTs signed before the rotation keep verifying during their natural
|
|
13
|
+
* lifetime instead of all logging out at the next request. Distinct from
|
|
14
|
+
* the timestamped audit `backup` files — `previousPublicPath` always
|
|
15
|
+
* lives at `oauth-previous-public.key` and gets overwritten on the next
|
|
16
|
+
* rotation. Null on first generation (no prior key to retain).
|
|
17
|
+
*/
|
|
18
|
+
previousPublicPath: string | null;
|
|
19
|
+
}
|
|
1
20
|
/**
|
|
2
21
|
* Generate RSA keypair for JWT signing.
|
|
3
22
|
* Writes to storage/oauth-private.key and storage/oauth-public.key.
|
|
23
|
+
*
|
|
24
|
+
* With `--force`, existing keys are renamed to `*.bak.<ISO-timestamp>` before
|
|
25
|
+
* being replaced AND the prior public key is also copied to
|
|
26
|
+
* `oauth-previous-public.key`. The verifier walks both keys during the
|
|
27
|
+
* grace window (until the prior tokens expire naturally), so a rotation no
|
|
28
|
+
* longer forces an immediate global sign-out. The audit backups live
|
|
29
|
+
* alongside for full recovery; the previous-public file is the operational
|
|
30
|
+
* one that the verifier consults.
|
|
4
31
|
*/
|
|
5
32
|
export declare function generateKeys(opts?: {
|
|
6
33
|
force?: boolean;
|
|
7
|
-
}): Promise<
|
|
8
|
-
privatePath: string;
|
|
9
|
-
publicPath: string;
|
|
10
|
-
}>;
|
|
34
|
+
}): Promise<GenerateKeysResult>;
|
|
11
35
|
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAG,MAAM,CAAA;IACnB,gFAAgF;IAChF,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC1D;;;;;;;;OAQG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAgD9F"}
|