@rudderjs/passport 1.0.0 → 1.1.1

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 (103) hide show
  1. package/boost/guidelines.md +190 -0
  2. package/dist/Passport.d.ts +93 -0
  3. package/dist/Passport.d.ts.map +1 -1
  4. package/dist/Passport.js +147 -0
  5. package/dist/Passport.js.map +1 -1
  6. package/dist/client-secret.d.ts +12 -0
  7. package/dist/client-secret.d.ts.map +1 -0
  8. package/dist/client-secret.js +63 -0
  9. package/dist/client-secret.js.map +1 -0
  10. package/dist/commands/client.d.ts +21 -0
  11. package/dist/commands/client.d.ts.map +1 -1
  12. package/dist/commands/client.js +27 -2
  13. package/dist/commands/client.js.map +1 -1
  14. package/dist/commands/keys.d.ts +28 -4
  15. package/dist/commands/keys.d.ts.map +1 -1
  16. package/dist/commands/keys.js +34 -4
  17. package/dist/commands/keys.js.map +1 -1
  18. package/dist/commands/purge.d.ts +6 -1
  19. package/dist/commands/purge.d.ts.map +1 -1
  20. package/dist/commands/purge.js +15 -31
  21. package/dist/commands/purge.js.map +1 -1
  22. package/dist/device-code-secret.d.ts +28 -0
  23. package/dist/device-code-secret.d.ts.map +1 -0
  24. package/dist/device-code-secret.js +31 -0
  25. package/dist/device-code-secret.js.map +1 -0
  26. package/dist/grants/authorization-code.d.ts +23 -0
  27. package/dist/grants/authorization-code.d.ts.map +1 -1
  28. package/dist/grants/authorization-code.js +126 -15
  29. package/dist/grants/authorization-code.js.map +1 -1
  30. package/dist/grants/client-credentials.d.ts.map +1 -1
  31. package/dist/grants/client-credentials.js +13 -5
  32. package/dist/grants/client-credentials.js.map +1 -1
  33. package/dist/grants/device-code.d.ts +10 -1
  34. package/dist/grants/device-code.d.ts.map +1 -1
  35. package/dist/grants/device-code.js +41 -10
  36. package/dist/grants/device-code.js.map +1 -1
  37. package/dist/grants/index.d.ts +1 -1
  38. package/dist/grants/index.d.ts.map +1 -1
  39. package/dist/grants/index.js +1 -1
  40. package/dist/grants/index.js.map +1 -1
  41. package/dist/grants/issue-tokens.d.ts +9 -0
  42. package/dist/grants/issue-tokens.d.ts.map +1 -1
  43. package/dist/grants/issue-tokens.js +39 -5
  44. package/dist/grants/issue-tokens.js.map +1 -1
  45. package/dist/grants/refresh-token.d.ts.map +1 -1
  46. package/dist/grants/refresh-token.js +64 -9
  47. package/dist/grants/refresh-token.js.map +1 -1
  48. package/dist/grants/safe-compare.d.ts +19 -0
  49. package/dist/grants/safe-compare.d.ts.map +1 -0
  50. package/dist/grants/safe-compare.js +28 -0
  51. package/dist/grants/safe-compare.js.map +1 -0
  52. package/dist/index.d.ts +27 -6
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +122 -67
  55. package/dist/index.js.map +1 -1
  56. package/dist/middleware/bearer.d.ts.map +1 -1
  57. package/dist/middleware/bearer.js +36 -6
  58. package/dist/middleware/bearer.js.map +1 -1
  59. package/dist/middleware/scope.d.ts +12 -2
  60. package/dist/middleware/scope.d.ts.map +1 -1
  61. package/dist/middleware/scope.js +46 -2
  62. package/dist/middleware/scope.js.map +1 -1
  63. package/dist/models/AccessToken.d.ts +32 -0
  64. package/dist/models/AccessToken.d.ts.map +1 -1
  65. package/dist/models/AccessToken.js +63 -3
  66. package/dist/models/AccessToken.js.map +1 -1
  67. package/dist/models/AuthCode.d.ts +16 -0
  68. package/dist/models/AuthCode.d.ts.map +1 -1
  69. package/dist/models/AuthCode.js +17 -1
  70. package/dist/models/AuthCode.js.map +1 -1
  71. package/dist/models/DeviceCode.d.ts +12 -2
  72. package/dist/models/DeviceCode.d.ts.map +1 -1
  73. package/dist/models/DeviceCode.js +7 -1
  74. package/dist/models/DeviceCode.js.map +1 -1
  75. package/dist/models/OAuthClient.d.ts +4 -0
  76. package/dist/models/OAuthClient.d.ts.map +1 -1
  77. package/dist/models/OAuthClient.js +13 -1
  78. package/dist/models/OAuthClient.js.map +1 -1
  79. package/dist/models/RefreshToken.d.ts +11 -0
  80. package/dist/models/RefreshToken.d.ts.map +1 -1
  81. package/dist/models/RefreshToken.js +12 -2
  82. package/dist/models/RefreshToken.js.map +1 -1
  83. package/dist/models/helpers.d.ts +6 -0
  84. package/dist/models/helpers.d.ts.map +1 -1
  85. package/dist/models/helpers.js +15 -2
  86. package/dist/models/helpers.js.map +1 -1
  87. package/dist/opaque-token.d.ts +32 -0
  88. package/dist/opaque-token.d.ts.map +1 -0
  89. package/dist/opaque-token.js +38 -0
  90. package/dist/opaque-token.js.map +1 -0
  91. package/dist/personal-access-tokens.d.ts.map +1 -1
  92. package/dist/personal-access-tokens.js +48 -10
  93. package/dist/personal-access-tokens.js.map +1 -1
  94. package/dist/routes.d.ts +149 -0
  95. package/dist/routes.d.ts.map +1 -1
  96. package/dist/routes.js +279 -41
  97. package/dist/routes.js.map +1 -1
  98. package/dist/token.d.ts +80 -4
  99. package/dist/token.d.ts.map +1 -1
  100. package/dist/token.js +97 -13
  101. package/dist/token.js.map +1 -1
  102. package/package.json +7 -6
  103. package/schema/passport.prisma +29 -9
@@ -0,0 +1,190 @@
1
+ # @rudderjs/passport
2
+
3
+ ## Overview
4
+
5
+ OAuth 2 server package — issues JWT access tokens, refresh tokens, and personal access tokens. Ships four grants (authorization code + PKCE, client credentials, refresh token, device code), a `HasApiTokens` mixin for user models, and `RequireBearer` + `scope` middleware for protecting API routes. JWTs are RS256-signed, so third parties can verify them without calling the server.
6
+
7
+ ## When to Use Passport vs Auth
8
+
9
+ `@rudderjs/auth` covers **session-based web auth** — login forms, cookies, password reset, email verification. `@rudderjs/passport` covers **token-based API auth** — OAuth flows for third-party integrations, M2M service auth, personal access tokens.
10
+
11
+ Most apps need both:
12
+
13
+ - **Web routes** (`m.web` group): `AuthMiddleware` runs automatically — read `req.user` directly.
14
+ - **API routes** (`m.api` group): stateless by default. Opt in per-route with `RequireBearer()` + `scope(...)`, or mount `AuthMiddleware('api')` + `RequireAuth('api')` with a token guard.
15
+
16
+ **Don't** mount `AuthMiddleware` globally via `m.use(...)`. API routes must stay stateless so they don't depend on session ALS context.
17
+
18
+ ## Key Patterns
19
+
20
+ ### Protecting API Routes
21
+
22
+ ```ts
23
+ import { RequireBearer, scope } from '@rudderjs/passport'
24
+
25
+ router.get('/api/user', [RequireBearer()], (req) => req.user)
26
+ router.get('/api/posts', [RequireBearer(), scope('read')], listPosts)
27
+ router.post('/api/posts', [RequireBearer(), scope('write')], createPost)
28
+ ```
29
+
30
+ `RequireBearer()` validates the JWT signature, checks expiration, and confirms the token hasn't been revoked in the DB. A valid token attaches the user to `req.user` (same shape as session-based routes).
31
+
32
+ `scope(...)` must run **after** `RequireBearer()` — it reads token scopes from request state set by the bearer middleware. Wildcard `*` grants everything.
33
+
34
+ ### Personal Access Tokens (HasApiTokens)
35
+
36
+ ```ts
37
+ import { Model } from '@rudderjs/orm'
38
+ import { HasApiTokens } from '@rudderjs/passport'
39
+
40
+ export class User extends HasApiTokens(Model) {
41
+ static table = 'user'
42
+ }
43
+
44
+ // Issue — plain-text JWT is shown ONCE
45
+ const { plainTextToken, token } = await user.createToken('my-cli', ['read', 'write'])
46
+
47
+ // Manage
48
+ await user.tokens() // all tokens for this user
49
+ await user.revokeAllTokens() // revokes all, returns count
50
+ user.tokenCan('admin') // checks current-request token's scope (inside RequireBearer route)
51
+ ```
52
+
53
+ Personal access tokens are issued against an internal `__personal_access__` OAuth client that Passport auto-creates on first use.
54
+
55
+ ### Route Registration
56
+
57
+ ```ts
58
+ // routes/api.ts
59
+ import { registerPassportRoutes } from '@rudderjs/passport'
60
+
61
+ export default (router) => {
62
+ registerPassportRoutes(router) // mounts /oauth/* endpoints
63
+ }
64
+
65
+ // Or selectively skip groups:
66
+ registerPassportRoutes(router, {
67
+ except: ['authorize', 'scopes'], // mount custom consent + scopes endpoints
68
+ prefix: '/api/oauth', // default is '/oauth'
69
+ })
70
+ ```
71
+
72
+ Available groups: `authorize`, `token`, `revoke`, `scopes`, `device`.
73
+
74
+ ### Customization Hooks
75
+
76
+ All hooks live on the `Passport` static singleton. Call them from a provider's `boot()` method, before routes register:
77
+
78
+ ```ts
79
+ import { Passport, OAuthClient } from '@rudderjs/passport'
80
+ import { view } from '@rudderjs/view'
81
+
82
+ // Custom consent screen (default returns JSON)
83
+ Passport.authorizationView((ctx) => {
84
+ return view('oauth.authorize', {
85
+ client: ctx.client,
86
+ scopes: ctx.scopes,
87
+ redirectUri: ctx.redirectUri,
88
+ state: ctx.state,
89
+ })
90
+ })
91
+
92
+ // Swap any model (add columns, override behavior)
93
+ class CustomOAuthClient extends OAuthClient { /* ... */ }
94
+ Passport.useClientModel(CustomOAuthClient)
95
+ // Also: useTokenModel, useRefreshTokenModel, useAuthCodeModel, useDeviceCodeModel
96
+
97
+ // Disable automatic route registration entirely
98
+ Passport.ignoreRoutes() // registerPassportRoutes() becomes a no-op
99
+
100
+ // Scopes can also be defined here instead of config
101
+ Passport.tokensCan({ read: 'Read access', write: 'Write access' })
102
+ ```
103
+
104
+ ### Config Shape
105
+
106
+ ```ts
107
+ // config/passport.ts
108
+ import type { PassportConfig } from '@rudderjs/passport'
109
+
110
+ export default {
111
+ scopes: { read: 'Read', write: 'Write', admin: 'Admin' },
112
+
113
+ // Keys — prefer env vars in production
114
+ privateKey: process.env.PASSPORT_PRIVATE_KEY,
115
+ publicKey: process.env.PASSPORT_PUBLIC_KEY,
116
+ // OR filesystem:
117
+ keyPath: 'storage', // reads storage/oauth-{private,public}.key
118
+
119
+ // Lifetimes (ms)
120
+ tokensExpireIn: 15 * 24 * 60 * 60 * 1000,
121
+ refreshTokensExpireIn: 30 * 24 * 60 * 60 * 1000,
122
+ personalAccessTokensExpireIn: 6 * 30 * 24 * 60 * 60 * 1000,
123
+ } satisfies PassportConfig
124
+ ```
125
+
126
+ ### CLI Commands
127
+
128
+ ```bash
129
+ pnpm rudder passport:keys [--force] # generate RSA keypair
130
+ pnpm rudder passport:client "App Name" [--public|--client-credentials|--device|--personal]
131
+ pnpm rudder passport:purge # remove expired/revoked records
132
+ pnpm rudder make:passport-client # scaffold a client seeder
133
+ ```
134
+
135
+ ## Common Pitfalls
136
+
137
+ - **Missing RSA keys** — run `pnpm rudder passport:keys` before issuing tokens, or set `PASSPORT_PRIVATE_KEY`/`PASSPORT_PUBLIC_KEY` env vars. Without keys, `passport.token()` throws.
138
+ - **Prisma schema not copied** — `@rudderjs/passport` ships 5 Prisma models in `schema/passport.prisma`. Copy that file into the app's multi-file Prisma schema directory and run `prisma db push`. The provider does not migrate for you.
139
+ - **Mounting `AuthMiddleware` globally breaks API routes** — `@rudderjs/auth`'s `AuthMiddleware` auto-installs on the `web` group only. API routes stay stateless; opt into auth per-route with `RequireBearer()`. Never call `m.use(AuthMiddleware())` — it reintroduces the old global-install problem.
140
+ - **Scope middleware before bearer** — `scope('read')` must come after `RequireBearer()` in the middleware array; it reads the token scopes the bearer middleware attaches to the request.
141
+ - **PKCE required for public clients** — public clients (created with `--public`) must send `code_challenge` + `code_challenge_method=S256`. Missing PKCE → `invalid_request`.
142
+ - **Refresh token reuse** — rotation revokes the old refresh token atomically. Retrying with the old one returns `invalid_grant`.
143
+ - **ORM returns records, not Model instances** — `AccessToken.where(...).first()` returns a plain data object. Prototype methods don't work on query results. Use `@rudderjs/passport`'s `models/helpers.ts` helpers (e.g. `accessTokenHelpers.can(token, scope)`) rather than calling methods on the record.
144
+ - **Custom model `static table`** — use the Prisma delegate name (camelCase, e.g. `oauthClient`), NOT the `@@map`'d SQL name (`oauth_clients`). Wrong table name → `[RudderJS ORM] Prisma has no delegate for table "oauth_clients"`.
145
+ - **Consent screen needs session** — `POST /oauth/authorize` and `POST /oauth/device/approve` both require `req.user`. If you mount OAuth routes on the `api` group, these two routes will 401. Either keep consent + device-approve on the `web` group, or mount `SessionMiddleware()` + `AuthMiddleware()` per-route.
146
+ - **Personal access client cache** — `_personalClientId` is cached module-level. `resetPersonalAccessClient()` is test-only; don't call it in production code.
147
+ - **Don't store plain-text JWTs** — `user.createToken()` returns `plainTextToken` once. The DB stores only the record (used for revocation lookup via `jti`). Show the JWT to the user; they must save it themselves.
148
+
149
+ ## Key Imports
150
+
151
+ ```ts
152
+ // Middleware
153
+ import { RequireBearer, BearerMiddleware, scope } from '@rudderjs/passport'
154
+
155
+ // Personal access tokens (user model mixin)
156
+ import { HasApiTokens } from '@rudderjs/passport'
157
+
158
+ // Customization
159
+ import { Passport } from '@rudderjs/passport'
160
+
161
+ // Route registration
162
+ import { registerPassportRoutes } from '@rudderjs/passport'
163
+ import type { PassportRouteOptions, PassportRouteGroup } from '@rudderjs/passport'
164
+
165
+ // Grant primitives (for custom route handlers)
166
+ import {
167
+ validateAuthorizationRequest,
168
+ issueAuthCode,
169
+ exchangeAuthCode,
170
+ clientCredentialsGrant,
171
+ refreshTokenGrant,
172
+ requestDeviceCode,
173
+ pollDeviceCode,
174
+ approveDeviceCode,
175
+ OAuthError,
176
+ } from '@rudderjs/passport'
177
+
178
+ // Models
179
+ import { OAuthClient, AccessToken, RefreshToken, AuthCode, DeviceCode } from '@rudderjs/passport'
180
+
181
+ // JWT primitives
182
+ import { createToken, verifyToken, unsafeDecodeToken } from '@rudderjs/passport'
183
+ // `decodeToken` is kept as a deprecated alias for `unsafeDecodeToken`. The
184
+ // `unsafe` prefix is intentional — the function does NOT verify the
185
+ // signature, so its output cannot be trusted for auth decisions. Use
186
+ // `verifyToken` whenever you need an authenticated payload.
187
+
188
+ // Types
189
+ import type { PassportConfig, PassportScope, NewPersonalAccessToken } from '@rudderjs/passport'
190
+ ```
@@ -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":"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;IAG/C,OAAO,CAAC,MAAM,CAAC,YAAY,CAAyC;IACpE,OAAO,CAAC,MAAM,CAAC,WAAW,CAA0C;IACpE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAmC;IACpE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAuC;IACpE,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAqC;IAGpE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAmC;IAGpE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAQ;IAIrC,qCAAqC;IACrC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAMtD,mCAAmC;IACnC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIpC,8BAA8B;IAC9B,MAAM,CAAC,MAAM,IAAI,aAAa,EAAE;IAIhC,+DAA+D;IAC/D,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IAMjD,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IACvC,MAAM,CAAC,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAC9C,MAAM,CAAC,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAErD,MAAM,CAAC,aAAa,IAAI,MAAM;IAC9B,MAAM,CAAC,oBAAoB,IAAI,MAAM;IACrC,MAAM,CAAC,qBAAqB,IAAI,MAAM;IAItC,mDAAmD;IACnD,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAEvC,mCAAmC;IACnC,MAAM,CAAC,OAAO,IAAI,MAAM;IAExB,sDAAsD;IACtD,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAK3D,sEAAsE;WACzD,IAAI,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA0BvE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,WAAW,GAAU,IAAI;IAC3D,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,WAAW,GAAW,IAAI;IAC3D,MAAM,CAAC,oBAAoB,CAAC,GAAG,EAAE,OAAO,YAAY,GAAG,IAAI;IAC3D,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,OAAO,QAAQ,GAAW,IAAI;IAC3D,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,UAAU,GAAO,IAAI;WAE9C,WAAW,IAAI,OAAO,CAAC,OAAO,WAAW,CAAC;WAI1C,UAAU,IAAI,OAAO,CAAC,OAAO,WAAW,CAAC;WAIzC,iBAAiB,IAAI,OAAO,CAAC,OAAO,YAAY,CAAC;WAIjD,aAAa,IAAI,OAAO,CAAC,OAAO,QAAQ,CAAC;WAIzC,eAAe,IAAI,OAAO,CAAC,OAAO,UAAU,CAAC;IAO1D;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,EAAE,EAAE,mBAAmB,GAAG,IAAI;IAIvD,MAAM,CAAC,mBAAmB,IAAI,mBAAmB,GAAG,IAAI;IAMxD;;;OAGG;IACH,MAAM,CAAC,YAAY,IAAI,IAAI;IAI3B,MAAM,CAAC,aAAa,IAAI,OAAO;IAM/B,gBAAgB;IAChB,MAAM,CAAC,KAAK,IAAI,IAAI;CAgBrB"}
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":"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;IAC/C;;;;;;;;OAQG;IACK,MAAM,CAAC,kBAAkB,GAAkB,IAAI,CAAA;IAEvD,8FAA8F;IACtF,MAAM,CAAC,YAAY,GAAqC,IAAI,CAAA;IAC5D,MAAM,CAAC,WAAW,GAAsC,IAAI,CAAA;IAC5D,MAAM,CAAC,kBAAkB,GAA+B,IAAI,CAAA;IAC5D,MAAM,CAAC,cAAc,GAAmC,IAAI,CAAA;IAC5D,MAAM,CAAC,gBAAgB,GAAiC,IAAI,CAAA;IAEpE,sBAAsB;IACd,MAAM,CAAC,kBAAkB,GAA+B,IAAI,CAAA;IAEpE,iCAAiC;IACzB,MAAM,CAAC,cAAc,GAAG,KAAK,CAAA;IAErC,yEAAyE;IACzE,0EAA0E;IAC1E,0EAA0E;IAC1E,uEAAuE;IAC/D,MAAM,CAAC,OAAO,GAAkB,IAAI,CAAA;IAE5C;;;;;;;OAOG;IACK,MAAM,CAAC,kBAAkB,GAAG,EAAE,CAAA;IAEtC,2DAA2D;IAE3D,qCAAqC;IACrC,MAAM,CAAC,SAAS,CAAC,MAA8B;QAC7C,KAAK,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,MAAM,CAAC,QAAQ,CAAC,EAAU;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,8BAA8B;IAC9B,MAAM,CAAC,MAAM;QACX,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;IACtF,CAAC;IAED,+DAA+D;IAC/D,MAAM,CAAC,WAAW,CAAC,SAAmB;QACpC,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;IAChE,CAAC;IAED,2DAA2D;IAE3D,MAAM,CAAC,cAAc,CAAC,EAAU,IAAU,IAAI,CAAC,cAAc,GAAG,EAAE,CAAA,CAAC,CAAC;IACpE,MAAM,CAAC,qBAAqB,CAAC,EAAU,IAAU,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAA,CAAC,CAAC;IAClF,MAAM,CAAC,4BAA4B,CAAC,EAAU,IAAU,IAAI,CAAC,sBAAsB,GAAG,EAAE,CAAA,CAAC,CAAC;IAE1F,MAAM,CAAC,aAAa,KAAa,OAAO,IAAI,CAAC,cAAc,CAAA,CAAC,CAAC;IAC7D,MAAM,CAAC,oBAAoB,KAAa,OAAO,IAAI,CAAC,qBAAqB,CAAA,CAAC,CAAC;IAC3E,MAAM,CAAC,qBAAqB,KAAa,OAAO,IAAI,CAAC,sBAAsB,CAAA,CAAC,CAAC;IAE7E,2DAA2D;IAE3D,mDAAmD;IACnD,MAAM,CAAC,YAAY,CAAC,IAAY,IAAU,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA,CAAC,CAAC;IAEhE,mCAAmC;IACnC,MAAM,CAAC,OAAO,KAAa,OAAO,IAAI,CAAC,QAAQ,CAAA,CAAC,CAAC;IAEjD,sDAAsD;IACtD,MAAM,CAAC,OAAO,CAAC,UAAkB,EAAE,SAAiB;QAClD,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;QAC7B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;IAC7B,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,oBAAoB,CAAC,SAAwB;QAClD,IAAI,CAAC,kBAAkB,GAAG,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;IAChF,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa;QACxB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAA;QAEpD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QACjD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;QAE1C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;QAC3E,MAAM,UAAU,GAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAA;QAE1E,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC;YAC/C,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC;SAC/C,CAAC,CAAA;QACF,OAAO,IAAI,IAAI,GAAG,CAAA;IACpB,CAAC;IAED,sEAAsE;IACtE,MAAM,CAAC,KAAK,CAAC,IAAI;QACf,6CAA6C;QAC7C,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,CAAA;QACrE,CAAC;QAED,uBAAuB;QACvB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;QAE1C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;QAC3E,MAAM,UAAU,GAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAA;QAE1E,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;YAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;SAC7B,CAAC,CAAA;QAEF,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;QAC7B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;QAE3B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAA;IAClC,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB;QAC3B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACvC,MAAM,IAAI,GAAa,CAAC,SAAS,CAAC,CAAA;QAElC,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;YAClC,OAAO,IAAI,CAAA;QACb,CAAC;QAED,kEAAkE;QAClE,mEAAmE;QACnE,4BAA4B;QAC5B,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;QAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAA;QACpF,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;YACrD,IAAI,CAAC,kBAAkB,GAAG,QAAQ,CAAA;YAClC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,0DAA0D;QAC5D,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAED,sDAAsD;IACtD,MAAM,CAAC,iBAAiB;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAA;IAChC,CAAC;IAED,2DAA2D;IAE3D,MAAM,CAAC,cAAc,CAAC,GAAuB,IAAiB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAA,CAAC,CAAC;IACvF,MAAM,CAAC,aAAa,CAAC,GAAuB,IAAkB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAA,CAAC,CAAC;IACtF,MAAM,CAAC,oBAAoB,CAAC,GAAwB,IAAU,IAAI,CAAC,kBAAkB,GAAG,GAAG,CAAA,CAAC,CAAC;IAC7F,MAAM,CAAC,gBAAgB,CAAC,GAAoB,IAAkB,IAAI,CAAC,cAAc,GAAG,GAAG,CAAA,CAAC,CAAC;IACzF,MAAM,CAAC,kBAAkB,CAAC,GAAsB,IAAc,IAAI,CAAC,gBAAgB,GAAG,GAAG,CAAA,CAAC,CAAC;IAE3F,MAAM,CAAC,KAAK,CAAC,WAAW;QACtB,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,YAAY,CAAA;QAC/C,OAAO,CAAC,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC,WAAW,CAAA;IAC9D,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,UAAU;QACrB,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,WAAW,CAAA;QAC7C,OAAO,CAAC,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC,WAAW,CAAA;IAC9D,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,iBAAiB;QAC5B,IAAI,IAAI,CAAC,kBAAkB;YAAE,OAAO,IAAI,CAAC,kBAAkB,CAAA;QAC3D,OAAO,CAAC,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC,YAAY,CAAA;IAChE,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,aAAa;QACxB,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC,cAAc,CAAA;QACnD,OAAO,CAAC,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAA;IACxD,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,eAAe;QAC1B,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO,IAAI,CAAC,gBAAgB,CAAA;QACvD,OAAO,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,UAAU,CAAA;IAC5D,CAAC;IAED,2DAA2D;IAE3D;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,EAAuB;QAC9C,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,mBAAmB;QACxB,OAAO,IAAI,CAAC,kBAAkB,CAAA;IAChC,CAAC;IAED,2DAA2D;IAE3D;;;OAGG;IACH,MAAM,CAAC,YAAY;QACjB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;IAC5B,CAAC;IAED,MAAM,CAAC,aAAa;QAClB,OAAO,IAAI,CAAC,cAAc,CAAA;IAC5B,CAAC;IAED,2DAA2D;IAE3D;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,SAAS,CAAC,GAAW,IAAU,IAAI,CAAC,OAAO,GAAG,GAAG,IAAI,IAAI,CAAA,CAAC,CAAC;IAClE,MAAM,CAAC,MAAM,KAAoB,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IAEtD,2DAA2D;IAE3D;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CAAC,OAAe;QACtC,gEAAgE;QAChE,wDAAwD;QACxD,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IAC5D,CAAC;IAED,8DAA8D;IAC9D,MAAM,CAAC,wBAAwB;QAC7B,OAAO,IAAI,CAAC,kBAAkB,CAAA;IAChC,CAAC;IAED,2DAA2D;IAE3D,gBAAgB;IAChB,MAAM,CAAC,KAAK;QACV,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;QACpB,IAAI,CAAC,cAAc,GAAW,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QACtD,IAAI,CAAC,qBAAqB,GAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QACtD,IAAI,CAAC,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QAC1D,IAAI,CAAC,QAAQ,GAAM,SAAS,CAAA;QAC5B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;QACvB,IAAI,CAAC,UAAU,GAAI,IAAI,CAAA;QACvB,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAA;QAC9B,IAAI,CAAC,YAAY,GAAS,IAAI,CAAA;QAC9B,IAAI,CAAC,WAAW,GAAU,IAAI,CAAA;QAC9B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAA;QAC9B,IAAI,CAAC,cAAc,GAAO,IAAI,CAAA;QAC9B,IAAI,CAAC,gBAAgB,GAAK,IAAI,CAAA;QAC9B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAA;QAC9B,IAAI,CAAC,cAAc,GAAO,KAAK,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAc,IAAI,CAAA;QAC9B,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAA;IAC9B,CAAC"}
@@ -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"}