@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.
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
package/dist/index.js CHANGED
@@ -1,23 +1,26 @@
1
1
  import { ServiceProvider, config } from '@rudderjs/core';
2
2
  // ─── Re-exports ───────────────────────────────────────────
3
3
  export { Passport } from './Passport.js';
4
- export { createToken, verifyToken, decodeToken } from './token.js';
4
+ export { createToken, verifyToken, unsafeDecodeToken, decodeToken } from './token.js';
5
5
  export { OAuthClient } from './models/OAuthClient.js';
6
6
  export { AccessToken } from './models/AccessToken.js';
7
7
  export { RefreshToken } from './models/RefreshToken.js';
8
8
  export { AuthCode } from './models/AuthCode.js';
9
9
  export { DeviceCode } from './models/DeviceCode.js';
10
10
  export { BearerMiddleware, RequireBearer } from './middleware/bearer.js';
11
- export { scope } from './middleware/scope.js';
11
+ export { scope, scopeAny } from './middleware/scope.js';
12
12
  export { generateKeys } from './commands/keys.js';
13
- export { createClient } from './commands/client.js';
13
+ export { createClient, resolveClientGrantTypes } from './commands/client.js';
14
14
  export { purgeTokens } from './commands/purge.js';
15
+ export { hashClientSecret, verifyClientSecret } from './client-secret.js';
16
+ export { hashDeviceSecret } from './device-code-secret.js';
17
+ export { hashOpaqueToken, newOpaqueToken } from './opaque-token.js';
15
18
  // Grants
16
- export { issueTokens, validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, OAuthError, clientCredentialsGrant, refreshTokenGrant, requestDeviceCode, approveDeviceCode, pollDeviceCode, } from './grants/index.js';
19
+ export { issueTokens, validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, validateScopes, OAuthError, clientCredentialsGrant, refreshTokenGrant, requestDeviceCode, approveDeviceCode, pollDeviceCode, } from './grants/index.js';
17
20
  // Personal access tokens
18
21
  export { HasApiTokens, resetPersonalAccessClient } from './personal-access-tokens.js';
19
22
  // Routes
20
- export { registerPassportRoutes } from './routes.js';
23
+ export { registerPassportRoutes, registerPassportWebRoutes, registerPassportApiRoutes } from './routes.js';
21
24
  // ─── Service Provider ─────────────────────────────────────
22
25
  export class PassportProvider extends ServiceProvider {
23
26
  register() { }
@@ -31,6 +34,15 @@ export class PassportProvider extends ServiceProvider {
31
34
  else if (cfg.keyPath) {
32
35
  Passport.loadKeysFrom(cfg.keyPath);
33
36
  }
37
+ // Surface a startup warning when no keys are reachable — env vars
38
+ // unset AND no keypair on disk under the configured path. Without this,
39
+ // the first `/oauth/*` request fails deep inside `Passport.keys()` with
40
+ // a generic ENOENT that doesn't point at the missing-bootstrap-step.
41
+ if (!(await Passport.keysAvailable())) {
42
+ console.warn(`[@rudderjs/passport] No RSA keypair found at "${Passport.keyPath()}/oauth-{private,public}.key" ` +
43
+ `and no PASSPORT_PRIVATE_KEY / PASSPORT_PUBLIC_KEY env vars set. ` +
44
+ `Run \`rudder passport:keys\` to generate one — token issuance and verification will fail until keys are present.`);
45
+ }
34
46
  // Configure lifetimes
35
47
  if (cfg.tokensExpireIn)
36
48
  Passport.tokensExpireIn(cfg.tokensExpireIn);
@@ -41,64 +53,111 @@ export class PassportProvider extends ServiceProvider {
41
53
  // Configure scopes
42
54
  if (cfg.scopes)
43
55
  Passport.tokensCan(cfg.scopes);
56
+ // Configure issuer (P7) — see PassportConfig.issuer jsdoc.
57
+ if (cfg.issuer)
58
+ Passport.useIssuer(cfg.issuer);
59
+ // Device-flow polling cap — see PassportConfig.deviceMaxInterval jsdoc.
60
+ if (cfg.deviceMaxInterval !== undefined)
61
+ Passport.deviceMaxInterval(cfg.deviceMaxInterval);
44
62
  this.app.instance('passport', Passport);
45
- // Register CLI commands
46
- try {
47
- const { rudder } = await import('@rudderjs/core');
48
- rudder.command('passport:keys', async (args) => {
49
- const force = args.includes('--force');
50
- const { generateKeys } = await import('./commands/keys.js');
51
- const { privatePath, publicPath } = await generateKeys({ force });
52
- console.log(` RSA keys generated:`);
53
- console.log(` Private: ${privatePath}`);
54
- console.log(` Public: ${publicPath}`);
55
- }).description('Generate RSA encryption keys for OAuth tokens');
56
- rudder.command('passport:client', async (args) => {
57
- const name = args[0] ?? 'My App';
58
- const isPublic = args.includes('--public');
59
- const isDevice = args.includes('--device');
60
- const isPersonal = args.includes('--personal');
61
- const isM2M = args.includes('--client-credentials');
62
- const grantTypes = isDevice
63
- ? ['urn:ietf:params:oauth:grant-type:device_code']
64
- : isPersonal
65
- ? ['personal_access']
66
- : isM2M
67
- ? ['client_credentials']
68
- : ['authorization_code', 'refresh_token'];
69
- const { createClient } = await import('./commands/client.js');
70
- const { client, secret } = await createClient({
71
- name,
72
- confidential: !isPublic && !isDevice,
73
- grantTypes,
74
- });
75
- console.log(` OAuth client created:`);
76
- console.log(` Client ID: ${client.id}`);
77
- console.log(` Name: ${client.name}`);
78
- if (secret) {
79
- console.log(` Secret: ${secret}`);
80
- console.log(` (Store this secret — it won't be shown again.)`);
63
+ // Register the four token models with the ORM ModelRegistry so the
64
+ // `model:prune` scheduler picks up their `static prunable()` definitions
65
+ // on day-1 fresh apps without this, the registry only learns about
66
+ // the models lazily on the first oauth flow that hits them, so a fresh
67
+ // install running `model:prune` before any client/token activity would
68
+ // silently skip passport rows. Resolves through the `Passport.*Model()`
69
+ // accessors so app-level model overrides (`Passport.useTokenModel(...)`)
70
+ // are respected.
71
+ const { ModelRegistry } = await import('@rudderjs/orm');
72
+ ModelRegistry.register(await Passport.clientModel());
73
+ ModelRegistry.register(await Passport.tokenModel());
74
+ ModelRegistry.register(await Passport.refreshTokenModel());
75
+ ModelRegistry.register(await Passport.authCodeModel());
76
+ ModelRegistry.register(await Passport.deviceCodeModel());
77
+ // Register CLI commands. `@rudderjs/core` (which re-exports `rudder`)
78
+ // and `@rudderjs/console` (which exports `registerMakeSpecs`) are both
79
+ // hard deps via the `@rudderjs/core` → `@rudderjs/console` dependency
80
+ // chain, so the dynamic imports are guaranteed to resolve. We do NOT
81
+ // wrap registration in a catch-all — duplicate-registration bugs after
82
+ // HMR or stub-validation errors should surface, not get swallowed
83
+ // under a misleading "rudder not available" comment.
84
+ const { rudder } = await import('@rudderjs/core');
85
+ rudder.command('passport:keys', async (args) => {
86
+ const force = args.includes('--force');
87
+ const { generateKeys } = await import('./commands/keys.js');
88
+ const { privatePath, publicPath, backup, previousPublicPath } = await generateKeys({ force });
89
+ console.log(` RSA keys generated:`);
90
+ console.log(` Private: ${privatePath}`);
91
+ console.log(` Public: ${publicPath}`);
92
+ if (backup) {
93
+ console.log(` Previous keys backed up to:`);
94
+ console.log(` Private: ${backup.privatePath}`);
95
+ console.log(` Public: ${backup.publicPath}`);
96
+ if (previousPublicPath) {
97
+ console.log(` Previous public key retained for grace verification at:`);
98
+ console.log(` ${previousPublicPath}`);
99
+ console.log(` JWTs signed by the old key continue verifying until they expire.`);
100
+ console.log(` Delete this file once the old tokens have expired to drop the grace window.`);
81
101
  }
82
- }).description('Create a new OAuth client');
83
- rudder.command('passport:purge', async () => {
84
- const { purgeTokens } = await import('./commands/purge.js');
85
- const counts = await purgeTokens();
86
- const total = counts.accessTokens + counts.refreshTokens + counts.authCodes + counts.deviceCodes;
87
- console.log(` Purged ${total} expired/revoked record(s):`);
88
- console.log(` Access tokens: ${counts.accessTokens}`);
89
- console.log(` Refresh tokens: ${counts.refreshTokens}`);
90
- console.log(` Auth codes: ${counts.authCodes}`);
91
- console.log(` Device codes: ${counts.deviceCodes}`);
92
- }).description('Remove expired tokens and auth codes');
93
- // Register make:* scaffolder for passport
94
- try {
95
- const { registerMakeSpecs } = await import('@rudderjs/console');
96
- registerMakeSpecs({
97
- command: 'make:passport-client',
98
- description: 'Create a new OAuth client seeder',
99
- label: 'Passport client seeder created',
100
- directory: 'app/Seeders',
101
- stub: (className) => `import { createClient } from '@rudderjs/passport'
102
+ }
103
+ }).description('Generate RSA encryption keys for OAuth tokens');
104
+ rudder.command('passport:client', async (args) => {
105
+ const name = args[0] ?? 'My App';
106
+ const isPublic = args.includes('--public');
107
+ const isDevice = args.includes('--device');
108
+ const isPersonal = args.includes('--personal');
109
+ const isM2M = args.includes('--client-credentials');
110
+ // `--personal` previously created an OAuth client with `personal_access`
111
+ // as the only grant type — but `personal_access` is not an HTTP grant
112
+ // (`/oauth/token` rejects it), and personal access tokens go through
113
+ // `HasApiTokens.createToken()` which auto-manages an internal
114
+ // `__personal_access__` client. So the row a user got from
115
+ // `passport:client --personal` was an orphan — present in the DB,
116
+ // never reachable through any flow. Print a hint instead of creating
117
+ // it; this is a CLI ergonomics fix, no user-data migration needed.
118
+ if (isPersonal) {
119
+ console.log('Personal access tokens don\'t need a hand-rolled OAuth client.');
120
+ console.log('They\'re minted by HasApiTokens.createToken() against an auto-managed');
121
+ console.log('internal client; mix `HasApiTokens` into your User model and call:');
122
+ console.log('');
123
+ console.log(' const { plainTextToken } = await user.createToken(\'cli\', [\'read\'])');
124
+ console.log('');
125
+ console.log('See packages/passport/CLAUDE.md for the full setup.');
126
+ return;
127
+ }
128
+ const { createClient, resolveClientGrantTypes } = await import('./commands/client.js');
129
+ const grantTypes = resolveClientGrantTypes({ isDevice, isM2M });
130
+ const { client, secret } = await createClient({
131
+ name,
132
+ confidential: !isPublic && !isDevice,
133
+ grantTypes,
134
+ });
135
+ console.log(` OAuth client created:`);
136
+ console.log(` Client ID: ${client.id}`);
137
+ console.log(` Name: ${client.name}`);
138
+ if (secret) {
139
+ console.log(` Secret: ${secret}`);
140
+ console.log(` (Store this secret — it won't be shown again.)`);
141
+ }
142
+ }).description('Create a new OAuth client');
143
+ rudder.command('passport:purge', async () => {
144
+ const { purgeTokens } = await import('./commands/purge.js');
145
+ const counts = await purgeTokens();
146
+ const total = counts.accessTokens + counts.refreshTokens + counts.authCodes + counts.deviceCodes;
147
+ console.log(` Purged ${total} expired/revoked record(s):`);
148
+ console.log(` Access tokens: ${counts.accessTokens}`);
149
+ console.log(` Refresh tokens: ${counts.refreshTokens}`);
150
+ console.log(` Auth codes: ${counts.authCodes}`);
151
+ console.log(` Device codes: ${counts.deviceCodes}`);
152
+ }).description('Remove expired tokens and auth codes');
153
+ // Register make:* scaffolder for passport
154
+ const { registerMakeSpecs } = await import('@rudderjs/console');
155
+ registerMakeSpecs({
156
+ command: 'make:passport-client',
157
+ description: 'Create a new OAuth client seeder',
158
+ label: 'Passport client seeder created',
159
+ directory: 'app/Seeders',
160
+ stub: (className) => `import { createClient } from '@rudderjs/passport'
102
161
 
103
162
  export async function ${className.replace(/Seeder$/, '').toLowerCase()}Clients(): Promise<void> {
104
163
  // Create a confidential client (server-side apps)
@@ -107,15 +166,11 @@ export async function ${className.replace(/Seeder$/, '').toLowerCase()}Clients()
107
166
  redirectUri: 'http://localhost:3000/callback',
108
167
  grantTypes: ['authorization_code', 'refresh_token'],
109
168
  })
110
- console.log('Client ID:', (client as any).id)
169
+ console.log('Client ID:', client.id)
111
170
  console.log('Secret:', secret)
112
171
  }
113
172
  `,
114
- });
115
- }
116
- catch { /* rudder not available */ }
117
- }
118
- catch { /* rudder not available */ }
173
+ });
119
174
  }
120
175
  }
121
176
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"bearer.d.ts","sourceRoot":"","sources":["../../src/middleware/bearer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAK5D;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,iBAAiB,CAmDpD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,iBAAiB,CAiDjD"}
1
+ {"version":3,"file":"bearer.d.ts","sourceRoot":"","sources":["../../src/middleware/bearer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAmB5D;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,iBAAiB,CAyDpD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,iBAAiB,CAuDjD"}
@@ -1,5 +1,21 @@
1
1
  import { verifyToken } from '../token.js';
2
2
  import { Passport } from '../Passport.js';
3
+ /**
4
+ * Extract the Bearer-scheme credential from an Authorization header.
5
+ * RFC 6750 §2.1 / RFC 7235 §2.1 — the auth scheme is a token and must be
6
+ * matched case-insensitively, so `bearer xyz` and `BEARER xyz` are valid.
7
+ * Returns the trimmed credential, or null if the header is absent or the
8
+ * scheme is not "Bearer".
9
+ */
10
+ function extractBearer(authHeader) {
11
+ if (!authHeader)
12
+ return null;
13
+ if (authHeader.length < 7)
14
+ return null;
15
+ if (authHeader.slice(0, 7).toLowerCase() !== 'bearer ')
16
+ return null;
17
+ return authHeader.slice(7).trim() || null;
18
+ }
3
19
  /**
4
20
  * Middleware that authenticates via Bearer token (JWT).
5
21
  * Validates the JWT signature, checks expiration, checks revocation in DB.
@@ -8,13 +24,18 @@ import { Passport } from '../Passport.js';
8
24
  export function BearerMiddleware() {
9
25
  return async function BearerMiddleware(req, _res, next) {
10
26
  const authHeader = req.headers['authorization'];
11
- if (!authHeader?.startsWith('Bearer ')) {
27
+ const jwt = extractBearer(authHeader);
28
+ if (!jwt) {
12
29
  await next();
13
30
  return;
14
31
  }
15
- const jwt = authHeader.slice(7).trim();
16
32
  try {
17
- const payload = await verifyToken(jwt);
33
+ // Pass expectedIssuer when configured so verifyToken rejects
34
+ // tokens minted by an unrelated issuer sharing the same keypair
35
+ // (multi-tenant / staging+prod). Tokens with no `iss` claim are
36
+ // legacy and exempt — see verifyToken jsdoc.
37
+ const issuer = Passport.issuer();
38
+ const payload = await verifyToken(jwt, issuer ? { expectedIssuer: issuer } : undefined);
18
39
  // Check revocation in DB
19
40
  const AccessTokenCls = await Passport.tokenModel();
20
41
  const token = await AccessTokenCls.query()
@@ -36,6 +57,8 @@ export function BearerMiddleware() {
36
57
  const manager = app().make('auth.manager');
37
58
  const user = await manager.guard().provider.retrieveById(payload.sub);
38
59
  if (user) {
60
+ ;
61
+ user['__passport_token'] = token;
39
62
  const plain = {};
40
63
  for (const [k, v] of Object.entries(user)) {
41
64
  if (typeof v !== 'function' && k !== 'password')
@@ -63,13 +86,18 @@ export function BearerMiddleware() {
63
86
  export function RequireBearer() {
64
87
  return async function RequireBearer(req, res, next) {
65
88
  const authHeader = req.headers['authorization'];
66
- if (!authHeader?.startsWith('Bearer ')) {
89
+ const jwt = extractBearer(authHeader);
90
+ if (!jwt) {
67
91
  res.status(401).json({ error: 'unauthenticated', message: 'Bearer token required.' });
68
92
  return;
69
93
  }
70
- const jwt = authHeader.slice(7).trim();
71
94
  try {
72
- const payload = await verifyToken(jwt);
95
+ // Pass expectedIssuer when configured so verifyToken rejects
96
+ // tokens minted by an unrelated issuer sharing the same keypair
97
+ // (multi-tenant / staging+prod). Tokens with no `iss` claim are
98
+ // legacy and exempt — see verifyToken jsdoc.
99
+ const issuer = Passport.issuer();
100
+ const payload = await verifyToken(jwt, issuer ? { expectedIssuer: issuer } : undefined);
73
101
  // Check revocation
74
102
  const AccessTokenCls = await Passport.tokenModel();
75
103
  const token = await AccessTokenCls.query()
@@ -89,6 +117,8 @@ export function RequireBearer() {
89
117
  const manager = app().make('auth.manager');
90
118
  const user = await manager.guard().provider.retrieveById(payload.sub);
91
119
  if (user) {
120
+ ;
121
+ user['__passport_token'] = token;
92
122
  const plain = {};
93
123
  for (const [k, v] of Object.entries(user)) {
94
124
  if (typeof v !== 'function' && k !== 'password')
@@ -1 +1 @@
1
- {"version":3,"file":"bearer.js","sourceRoot":"","sources":["../../src/middleware/bearer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGzC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,KAAK,UAAU,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI;QACpD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAuB,CAAA;QACrE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACtC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;YAEtC,yBAAyB;YACzB,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAA;YAClD,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE;iBACvC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;iBACxB,KAAK,EAAwB,CAAA;YAEhC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC5B,MAAM,IAAI,EAAE,CAAA;gBACZ,OAAM;YACR,CAAC;YAED,uCAAuC;YACvC,MAAM,GAAG,GAAG,GAAG,CAAC,GAA8B,CAAA;YAC9C,GAAG,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAA;YAC/B,GAAG,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAA;YACzC,GAAG,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,GAAG,CAAA;YAEvC,mCAAmC;YACnC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;oBAC9C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAA4E,cAAc,CAAC,CAAA;oBACrH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;oBACrE,IAAI,IAAI,EAAE,CAAC;wBACT,MAAM,KAAK,GAA4B,EAAE,CAAA;wBACzC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;4BACrE,IAAI,OAAO,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,UAAU;gCAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;wBAC/D,CAAC;wBACD,GAAG,CAAC,YAAY,CAAC,GAAG,KAAK,CAAA;wBACzB,IAAI,CAAC;4BAAE,GAA0C,CAAC,MAAM,CAAC,GAAG,KAAK,CAAA;wBAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;oBAC/F,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,KAAK,UAAU,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI;QAChD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAuB,CAAA;QACrE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAA;YACrF,OAAM;QACR,CAAC;QAED,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACtC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;YAEtC,mBAAmB;YACnB,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAA;YAClD,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE;iBACvC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;iBACxB,KAAK,EAAwB,CAAA;YAEhC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAA;gBACtF,OAAM;YACR,CAAC;YAED,MAAM,GAAG,GAAG,GAAG,CAAC,GAA8B,CAAA;YAC9C,GAAG,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAA;YAC/B,GAAG,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAA;YACzC,GAAG,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,GAAG,CAAA;YAEvC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;oBAC9C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAA4E,cAAc,CAAC,CAAA;oBACrH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;oBACrE,IAAI,IAAI,EAAE,CAAC;wBACT,MAAM,KAAK,GAA4B,EAAE,CAAA;wBACzC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;4BACrE,IAAI,OAAO,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,UAAU;gCAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;wBAC/D,CAAC;wBACD,GAAG,CAAC,YAAY,CAAC,GAAG,KAAK,CAAA;wBACzB,IAAI,CAAC;4BAAE,GAA0C,CAAC,MAAM,CAAC,GAAG,KAAK,CAAA;wBAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;oBAC/F,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;YACtC,CAAC;YAED,MAAM,IAAI,EAAE,CAAA;QACd,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAA;QAC1F,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"bearer.js","sourceRoot":"","sources":["../../src/middleware/bearer.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,21 @@
1
1
  import type { MiddlewareHandler } from '@rudderjs/contracts';
2
2
  /**
3
- * Middleware that requires specific OAuth scopes on the Bearer token.
4
- * Must be used after BearerMiddleware or RequireBearer.
3
+ * Middleware that requires **all** listed OAuth scopes on the Bearer token
4
+ * (AND semantics). Must be used after BearerMiddleware or RequireBearer.
5
5
  *
6
6
  * @example
7
7
  * router.get('/admin', [RequireBearer(), scope('admin')], handler)
8
8
  * router.post('/orders', [RequireBearer(), scope('write', 'place-orders')], handler)
9
9
  */
10
10
  export declare function scope(...requiredScopes: string[]): MiddlewareHandler;
11
+ /**
12
+ * Middleware that requires **any** of the listed OAuth scopes on the Bearer
13
+ * token (OR semantics — Laravel's `scopes` vs `scope` middleware). Must be
14
+ * used after BearerMiddleware or RequireBearer.
15
+ *
16
+ * @example
17
+ * // Either scope is enough
18
+ * router.get('/orders', [RequireBearer(), scopeAny('orders:read', 'orders:write')], handler)
19
+ */
20
+ export declare function scopeAny(...allowedScopes: string[]): MiddlewareHandler;
11
21
  //# sourceMappingURL=scope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/middleware/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,GAAG,cAAc,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAiCpE"}
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/middleware/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,GAAG,cAAc,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAiCpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,aAAa,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAuCtE"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Middleware that requires specific OAuth scopes on the Bearer token.
3
- * Must be used after BearerMiddleware or RequireBearer.
2
+ * Middleware that requires **all** listed OAuth scopes on the Bearer token
3
+ * (AND semantics). Must be used after BearerMiddleware or RequireBearer.
4
4
  *
5
5
  * @example
6
6
  * router.get('/admin', [RequireBearer(), scope('admin')], handler)
@@ -36,4 +36,48 @@ export function scope(...requiredScopes) {
36
36
  await next();
37
37
  };
38
38
  }
39
+ /**
40
+ * Middleware that requires **any** of the listed OAuth scopes on the Bearer
41
+ * token (OR semantics — Laravel's `scopes` vs `scope` middleware). Must be
42
+ * used after BearerMiddleware or RequireBearer.
43
+ *
44
+ * @example
45
+ * // Either scope is enough
46
+ * router.get('/orders', [RequireBearer(), scopeAny('orders:read', 'orders:write')], handler)
47
+ */
48
+ export function scopeAny(...allowedScopes) {
49
+ return async function ScopeAnyMiddleware(req, res, next) {
50
+ const raw = req.raw;
51
+ const tokenScopes = raw['__passport_scopes'];
52
+ if (!tokenScopes) {
53
+ res.status(403).json({
54
+ error: 'insufficient_scope',
55
+ message: 'Token does not have any of the required scopes.',
56
+ required: allowedScopes,
57
+ });
58
+ return;
59
+ }
60
+ // Wildcard scope grants everything
61
+ if (tokenScopes.includes('*')) {
62
+ await next();
63
+ return;
64
+ }
65
+ // Calling scopeAny() with no arguments is a no-op safety net rather than
66
+ // an instant 403 — mirrors Laravel's behavior when the dev forgets the list.
67
+ if (allowedScopes.length === 0) {
68
+ await next();
69
+ return;
70
+ }
71
+ const matched = allowedScopes.some(s => tokenScopes.includes(s));
72
+ if (!matched) {
73
+ res.status(403).json({
74
+ error: 'insufficient_scope',
75
+ message: `Token must have at least one of: ${allowedScopes.join(', ')}`,
76
+ required: allowedScopes,
77
+ });
78
+ return;
79
+ }
80
+ await next();
81
+ };
82
+ }
39
83
  //# sourceMappingURL=scope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/middleware/scope.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,KAAK,CAAC,GAAG,cAAwB;IAC/C,OAAO,KAAK,UAAU,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI;QAClD,MAAM,GAAG,GAAG,GAAG,CAAC,GAA8B,CAAA;QAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,mBAAmB,CAAyB,CAAA;QAEpE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,0CAA0C;gBACnD,QAAQ,EAAE,cAAc;aACzB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,mCAAmC;QACnC,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QACpE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,8BAA8B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC3D,QAAQ,EAAE,cAAc;gBACxB,OAAO;aACR,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/middleware/scope.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,KAAK,CAAC,GAAG,cAAwB;IAC/C,OAAO,KAAK,UAAU,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI;QAClD,MAAM,GAAG,GAAG,GAAG,CAAC,GAA8B,CAAA;QAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,mBAAmB,CAAyB,CAAA;QAEpE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,0CAA0C;gBACnD,QAAQ,EAAE,cAAc;aACzB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,mCAAmC;QACnC,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QACpE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,8BAA8B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC3D,QAAQ,EAAE,cAAc;gBACxB,OAAO;aACR,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAG,aAAuB;IACjD,OAAO,KAAK,UAAU,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI;QACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAA8B,CAAA;QAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,mBAAmB,CAAyB,CAAA;QAEpE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,iDAAiD;gBAC1D,QAAQ,EAAE,aAAa;aACxB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,mCAAmC;QACnC,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,yEAAyE;QACzE,6EAA6E;QAC7E,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QAChE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,oCAAoC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACvE,QAAQ,EAAE,aAAa;aACxB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC"}
@@ -1,7 +1,39 @@
1
1
  import { Model } from '@rudderjs/orm';
2
+ /**
3
+ * Why we don't store hashed access tokens
4
+ * ----------------------------------------
5
+ * Unlike `@rudderjs/sanctum` (which stores SHA-256 hashes of opaque tokens),
6
+ * Passport access tokens are JWTs signed with RS256. The DB row records
7
+ * metadata only (`userId`, `clientId`, `scopes`, `revoked`, `expiresAt`); the
8
+ * JWT itself is never persisted. The signature is the secrecy boundary —
9
+ * anyone holding the JWT can verify it offline against the public key, and
10
+ * the only way to mint a valid one is with the private key.
11
+ *
12
+ * Practical consequences:
13
+ * - A DB dump does NOT leak usable bearer tokens. It leaks the audit trail
14
+ * (which user/client owns which token id, when it expires) but not the
15
+ * credential itself.
16
+ * - Revocation works by flipping `revoked = true`; bearer middleware checks
17
+ * the row on every request. JWT-only verification is intentionally not
18
+ * supported — we want revocation to be authoritative.
19
+ * - Rotating the signing keypair (`rudder passport:keys --force`) instantly
20
+ * invalidates every outstanding access token, since their signatures no
21
+ * longer verify under the new public key. See CLAUDE.md "Pitfalls".
22
+ *
23
+ * This matches Laravel Passport. If you want hashed-token semantics with
24
+ * no JWT verification step, use `@rudderjs/sanctum` instead.
25
+ */
2
26
  export declare class AccessToken extends Model {
3
27
  static table: string;
4
28
  static fillable: string[];
29
+ /** `MassPrunable` — bulk `deleteAll()` per chunk; mirrors `passport:purge`. */
30
+ static pruneMode: "mass";
31
+ /** Rows safe to remove: expired OR revoked. Same predicate as `passport:purge`. */
32
+ static prunable(): import("@rudderjs/contracts").QueryBuilder<AccessToken> & {
33
+ scope(name: string, ...args: unknown[]): import("@rudderjs/contracts").QueryBuilder<AccessToken>;
34
+ withoutGlobalScope(name: string): import("@rudderjs/contracts").QueryBuilder<AccessToken>;
35
+ };
36
+ id: string;
5
37
  userId: string | null;
6
38
  clientId: string;
7
39
  name: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"AccessToken.d.ts","sourceRoot":"","sources":["../../src/models/AccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAErC,qBAAa,WAAY,SAAQ,KAAK;IACpC,OAAgB,KAAK,SAAqB;IAE1C,OAAgB,QAAQ,WAAmE;IAEnF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,IAAI,CAAA;IAEvB,2BAA2B;IAC3B,SAAS,IAAI,MAAM,EAAE;IAMrB,+CAA+C;IAC/C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAK3B,sDAAsD;IACtD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI5B,yBAAyB;IACnB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7B,sCAAsC;IACtC,SAAS,IAAI,OAAO;IAIpB,iEAAiE;IACjE,OAAO,IAAI,OAAO;CAGnB"}
1
+ {"version":3,"file":"AccessToken.d.ts","sourceRoot":"","sources":["../../src/models/AccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAU,MAAM,eAAe,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,OAAgB,KAAK,SAAqB;IAQ1C,OAAgB,QAAQ,WAAwD;IAEhF,+EAA+E;IAC/E,MAAM,CAAC,SAAS,EAAG,MAAM,CAAS;IAElC,mFAAmF;IACnF,MAAM,CAAC,QAAQ;;;;IAMP,EAAE,EAAE,MAAM,CAAA;IAQV,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAGrB,QAAQ,EAAE,MAAM,CAAA;IAEhB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,IAAI,CAAA;IAEvB,2BAA2B;IAC3B,SAAS,IAAI,MAAM,EAAE;IAMrB,+CAA+C;IAC/C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAK3B,sDAAsD;IACtD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI5B,yBAAyB;IACnB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAU7B,sCAAsC;IACtC,SAAS,IAAI,OAAO;IAIpB,iEAAiE;IACjE,OAAO,IAAI,OAAO;CAGnB"}
@@ -1,7 +1,54 @@
1
- import { Model } from '@rudderjs/orm';
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Model, Hidden } from '@rudderjs/orm';
11
+ /**
12
+ * Why we don't store hashed access tokens
13
+ * ----------------------------------------
14
+ * Unlike `@rudderjs/sanctum` (which stores SHA-256 hashes of opaque tokens),
15
+ * Passport access tokens are JWTs signed with RS256. The DB row records
16
+ * metadata only (`userId`, `clientId`, `scopes`, `revoked`, `expiresAt`); the
17
+ * JWT itself is never persisted. The signature is the secrecy boundary —
18
+ * anyone holding the JWT can verify it offline against the public key, and
19
+ * the only way to mint a valid one is with the private key.
20
+ *
21
+ * Practical consequences:
22
+ * - A DB dump does NOT leak usable bearer tokens. It leaks the audit trail
23
+ * (which user/client owns which token id, when it expires) but not the
24
+ * credential itself.
25
+ * - Revocation works by flipping `revoked = true`; bearer middleware checks
26
+ * the row on every request. JWT-only verification is intentionally not
27
+ * supported — we want revocation to be authoritative.
28
+ * - Rotating the signing keypair (`rudder passport:keys --force`) instantly
29
+ * invalidates every outstanding access token, since their signatures no
30
+ * longer verify under the new public key. See CLAUDE.md "Pitfalls".
31
+ *
32
+ * This matches Laravel Passport. If you want hashed-token semantics with
33
+ * no JWT verification step, use `@rudderjs/sanctum` instead.
34
+ */
2
35
  export class AccessToken extends Model {
3
36
  static table = 'oAuthAccessToken';
4
- static fillable = ['userId', 'clientId', 'name', 'scopes', 'revoked', 'expiresAt'];
37
+ // `revoked` is intentionally NOT fillable flipping it is a privileged
38
+ // lifecycle operation that should only happen through `revoke()` (instance
39
+ // method) or `forceFill({ revoked: true })`. Allowing mass-assignment here
40
+ // would let any caller-controlled payload pre-mark a token as revoked
41
+ // before it ever sees real traffic. Defense-in-depth — no current route
42
+ // exposes this surface today.
43
+ static fillable = ['userId', 'clientId', 'name', 'scopes', 'expiresAt'];
44
+ /** `MassPrunable` — bulk `deleteAll()` per chunk; mirrors `passport:purge`. */
45
+ static pruneMode = 'mass';
46
+ /** Rows safe to remove: expired OR revoked. Same predicate as `passport:purge`. */
47
+ static prunable() {
48
+ return this.query()
49
+ .where('expiresAt', '<', new Date())
50
+ .orWhere('revoked', true);
51
+ }
5
52
  /** Parsed scopes array. */
6
53
  getScopes() {
7
54
  const raw = this['scopes'];
@@ -20,8 +67,13 @@ export class AccessToken extends Model {
20
67
  }
21
68
  /** Revoke this token. */
22
69
  async revoke() {
70
+ // Direct property assignment + save() bypasses the mass-assignment filter
71
+ // (`revoked` is no longer in `fillable`). Cleaner than the prior static
72
+ // `Model.update(id, ...)` pattern: observers fire normally, the in-memory
73
+ // instance reflects the new state without a re-read, and there's no
74
+ // `(this as any).id` cast that future refactors might silently break.
23
75
  this.revoked = true;
24
- await this.constructor.update(this.id, { revoked: true });
76
+ await this.save();
25
77
  }
26
78
  /** Whether this token has expired. */
27
79
  isExpired() {
@@ -32,4 +84,12 @@ export class AccessToken extends Model {
32
84
  return !this.revoked && !this.isExpired();
33
85
  }
34
86
  }
87
+ __decorate([
88
+ Hidden,
89
+ __metadata("design:type", Object)
90
+ ], AccessToken.prototype, "userId", void 0);
91
+ __decorate([
92
+ Hidden,
93
+ __metadata("design:type", String)
94
+ ], AccessToken.prototype, "clientId", void 0);
35
95
  //# sourceMappingURL=AccessToken.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccessToken.js","sourceRoot":"","sources":["../../src/models/AccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAErC,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,MAAM,CAAU,KAAK,GAAG,kBAAkB,CAAA;IAE1C,MAAM,CAAU,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;IAQ3F,2BAA2B;IAC3B,SAAS;QACP,MAAM,GAAG,GAAI,IAA2C,CAAC,QAAQ,CAAC,CAAA;QAClE,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAA;QAC/D,OAAQ,GAAgB,IAAI,EAAE,CAAA;IAChC,CAAC;IAED,+CAA+C;IAC/C,GAAG,CAAC,KAAa;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAA;QAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC,KAAa;QAChB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,yBAAyB;IACzB,KAAK,CAAC,MAAM;QACV,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,MAAO,IAAI,CAAC,WAAkC,CAAC,MAAM,CAAE,IAAY,CAAC,EAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAS,CAAC,CAAA;IAC7G,CAAC;IAED,sCAAsC;IACtC,SAAS;QACP,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA;IACzD,CAAC;IAED,iEAAiE;IACjE,OAAO;QACL,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;IAC3C,CAAC"}
1
+ {"version":3,"file":"AccessToken.js","sourceRoot":"","sources":["../../src/models/AccessToken.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,MAAM,CAAU,KAAK,GAAG,kBAAkB,CAAA;IAE1C,wEAAwE;IACxE,2EAA2E;IAC3E,2EAA2E;IAC3E,sEAAsE;IACtE,wEAAwE;IACxE,8BAA8B;IAC9B,MAAM,CAAU,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;IAEhF,+EAA+E;IAC/E,MAAM,CAAC,SAAS,GAAG,MAAe,CAAA;IAElC,mFAAmF;IACnF,MAAM,CAAC,QAAQ;QACb,OAAO,IAAI,CAAC,KAAK,EAAE;aAChB,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;aACnC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;IAmBD,2BAA2B;IAC3B,SAAS;QACP,MAAM,GAAG,GAAI,IAA2C,CAAC,QAAQ,CAAC,CAAA;QAClE,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAA;QAC/D,OAAQ,GAAgB,IAAI,EAAE,CAAA;IAChC,CAAC;IAED,+CAA+C;IAC/C,GAAG,CAAC,KAAa;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAA;QAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC,KAAa;QAChB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,yBAAyB;IACzB,KAAK,CAAC,MAAM;QACV,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,oEAAoE;QACpE,sEAAsE;QACtE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;IACnB,CAAC;IAED,sCAAsC;IACtC,SAAS;QACP,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA;IACzD,CAAC;IAED,iEAAiE;IACjE,OAAO;QACL,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;IAC3C,CAAC;;AA9CO;IADP,MAAM;;2CACsB;AAGrB;IADP,MAAM;;6CACiB"}