@rudderjs/passport 0.1.4 → 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.
Files changed (102) hide show
  1. package/dist/Passport.d.ts +93 -0
  2. package/dist/Passport.d.ts.map +1 -1
  3. package/dist/Passport.js +147 -0
  4. package/dist/Passport.js.map +1 -1
  5. package/dist/client-secret.d.ts +12 -0
  6. package/dist/client-secret.d.ts.map +1 -0
  7. package/dist/client-secret.js +63 -0
  8. package/dist/client-secret.js.map +1 -0
  9. package/dist/commands/client.d.ts +21 -0
  10. package/dist/commands/client.d.ts.map +1 -1
  11. package/dist/commands/client.js +27 -2
  12. package/dist/commands/client.js.map +1 -1
  13. package/dist/commands/keys.d.ts +28 -4
  14. package/dist/commands/keys.d.ts.map +1 -1
  15. package/dist/commands/keys.js +34 -4
  16. package/dist/commands/keys.js.map +1 -1
  17. package/dist/commands/purge.d.ts +6 -1
  18. package/dist/commands/purge.d.ts.map +1 -1
  19. package/dist/commands/purge.js +15 -31
  20. package/dist/commands/purge.js.map +1 -1
  21. package/dist/device-code-secret.d.ts +28 -0
  22. package/dist/device-code-secret.d.ts.map +1 -0
  23. package/dist/device-code-secret.js +31 -0
  24. package/dist/device-code-secret.js.map +1 -0
  25. package/dist/grants/authorization-code.d.ts +23 -0
  26. package/dist/grants/authorization-code.d.ts.map +1 -1
  27. package/dist/grants/authorization-code.js +126 -15
  28. package/dist/grants/authorization-code.js.map +1 -1
  29. package/dist/grants/client-credentials.d.ts.map +1 -1
  30. package/dist/grants/client-credentials.js +13 -5
  31. package/dist/grants/client-credentials.js.map +1 -1
  32. package/dist/grants/device-code.d.ts +10 -1
  33. package/dist/grants/device-code.d.ts.map +1 -1
  34. package/dist/grants/device-code.js +41 -10
  35. package/dist/grants/device-code.js.map +1 -1
  36. package/dist/grants/index.d.ts +1 -1
  37. package/dist/grants/index.d.ts.map +1 -1
  38. package/dist/grants/index.js +1 -1
  39. package/dist/grants/index.js.map +1 -1
  40. package/dist/grants/issue-tokens.d.ts +9 -0
  41. package/dist/grants/issue-tokens.d.ts.map +1 -1
  42. package/dist/grants/issue-tokens.js +39 -5
  43. package/dist/grants/issue-tokens.js.map +1 -1
  44. package/dist/grants/refresh-token.d.ts.map +1 -1
  45. package/dist/grants/refresh-token.js +64 -9
  46. package/dist/grants/refresh-token.js.map +1 -1
  47. package/dist/grants/safe-compare.d.ts +19 -0
  48. package/dist/grants/safe-compare.d.ts.map +1 -0
  49. package/dist/grants/safe-compare.js +28 -0
  50. package/dist/grants/safe-compare.js.map +1 -0
  51. package/dist/index.d.ts +27 -6
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +122 -67
  54. package/dist/index.js.map +1 -1
  55. package/dist/middleware/bearer.d.ts.map +1 -1
  56. package/dist/middleware/bearer.js +36 -6
  57. package/dist/middleware/bearer.js.map +1 -1
  58. package/dist/middleware/scope.d.ts +12 -2
  59. package/dist/middleware/scope.d.ts.map +1 -1
  60. package/dist/middleware/scope.js +46 -2
  61. package/dist/middleware/scope.js.map +1 -1
  62. package/dist/models/AccessToken.d.ts +32 -0
  63. package/dist/models/AccessToken.d.ts.map +1 -1
  64. package/dist/models/AccessToken.js +63 -3
  65. package/dist/models/AccessToken.js.map +1 -1
  66. package/dist/models/AuthCode.d.ts +16 -0
  67. package/dist/models/AuthCode.d.ts.map +1 -1
  68. package/dist/models/AuthCode.js +17 -1
  69. package/dist/models/AuthCode.js.map +1 -1
  70. package/dist/models/DeviceCode.d.ts +12 -2
  71. package/dist/models/DeviceCode.d.ts.map +1 -1
  72. package/dist/models/DeviceCode.js +7 -1
  73. package/dist/models/DeviceCode.js.map +1 -1
  74. package/dist/models/OAuthClient.d.ts +4 -0
  75. package/dist/models/OAuthClient.d.ts.map +1 -1
  76. package/dist/models/OAuthClient.js +13 -1
  77. package/dist/models/OAuthClient.js.map +1 -1
  78. package/dist/models/RefreshToken.d.ts +11 -0
  79. package/dist/models/RefreshToken.d.ts.map +1 -1
  80. package/dist/models/RefreshToken.js +12 -2
  81. package/dist/models/RefreshToken.js.map +1 -1
  82. package/dist/models/helpers.d.ts +6 -0
  83. package/dist/models/helpers.d.ts.map +1 -1
  84. package/dist/models/helpers.js +15 -2
  85. package/dist/models/helpers.js.map +1 -1
  86. package/dist/opaque-token.d.ts +32 -0
  87. package/dist/opaque-token.d.ts.map +1 -0
  88. package/dist/opaque-token.js +38 -0
  89. package/dist/opaque-token.js.map +1 -0
  90. package/dist/personal-access-tokens.d.ts.map +1 -1
  91. package/dist/personal-access-tokens.js +48 -10
  92. package/dist/personal-access-tokens.js.map +1 -1
  93. package/dist/routes.d.ts +149 -0
  94. package/dist/routes.d.ts.map +1 -1
  95. package/dist/routes.js +279 -41
  96. package/dist/routes.js.map +1 -1
  97. package/dist/token.d.ts +80 -4
  98. package/dist/token.d.ts.map +1 -1
  99. package/dist/token.js +97 -13
  100. package/dist/token.js.map +1 -1
  101. package/package.json +5 -5
  102. package/schema/passport.prisma +29 -9
@@ -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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Passport.d.ts","sourceRoot":"","sources":["../src/Passport.ts"],"names":[],"mappings":"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"}
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
@@ -1 +1 @@
1
- {"version":3,"file":"Passport.js","sourceRoot":"","sources":["../src/Passport.ts"],"names":[],"mappings":"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"}
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":"AACA,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;;;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"}
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"}
@@ -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, createHash } = await import('node:crypto');
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 = createHash('sha256').update(plainSecret).digest('hex');
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;AAUzC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAsB;IAIvD,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAE/D,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,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACvE,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"}
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"}
@@ -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;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBvH"}
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"}