@rudderjs/passport 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Passport.d.ts +93 -0
- package/dist/Passport.d.ts.map +1 -1
- package/dist/Passport.js +147 -0
- package/dist/Passport.js.map +1 -1
- package/dist/client-secret.d.ts +12 -0
- package/dist/client-secret.d.ts.map +1 -0
- package/dist/client-secret.js +63 -0
- package/dist/client-secret.js.map +1 -0
- package/dist/commands/client.d.ts +21 -0
- package/dist/commands/client.d.ts.map +1 -1
- package/dist/commands/client.js +27 -2
- package/dist/commands/client.js.map +1 -1
- package/dist/commands/keys.d.ts +28 -4
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +34 -4
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/purge.d.ts +6 -1
- package/dist/commands/purge.d.ts.map +1 -1
- package/dist/commands/purge.js +15 -31
- package/dist/commands/purge.js.map +1 -1
- package/dist/device-code-secret.d.ts +28 -0
- package/dist/device-code-secret.d.ts.map +1 -0
- package/dist/device-code-secret.js +31 -0
- package/dist/device-code-secret.js.map +1 -0
- package/dist/grants/authorization-code.d.ts +23 -0
- package/dist/grants/authorization-code.d.ts.map +1 -1
- package/dist/grants/authorization-code.js +126 -15
- package/dist/grants/authorization-code.js.map +1 -1
- package/dist/grants/client-credentials.d.ts.map +1 -1
- package/dist/grants/client-credentials.js +13 -5
- package/dist/grants/client-credentials.js.map +1 -1
- package/dist/grants/device-code.d.ts +10 -1
- package/dist/grants/device-code.d.ts.map +1 -1
- package/dist/grants/device-code.js +41 -10
- package/dist/grants/device-code.js.map +1 -1
- package/dist/grants/index.d.ts +1 -1
- package/dist/grants/index.d.ts.map +1 -1
- package/dist/grants/index.js +1 -1
- package/dist/grants/index.js.map +1 -1
- package/dist/grants/issue-tokens.d.ts +9 -0
- package/dist/grants/issue-tokens.d.ts.map +1 -1
- package/dist/grants/issue-tokens.js +39 -5
- package/dist/grants/issue-tokens.js.map +1 -1
- package/dist/grants/refresh-token.d.ts.map +1 -1
- package/dist/grants/refresh-token.js +64 -9
- package/dist/grants/refresh-token.js.map +1 -1
- package/dist/grants/safe-compare.d.ts +19 -0
- package/dist/grants/safe-compare.d.ts.map +1 -0
- package/dist/grants/safe-compare.js +28 -0
- package/dist/grants/safe-compare.js.map +1 -0
- package/dist/index.d.ts +27 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -67
- package/dist/index.js.map +1 -1
- package/dist/middleware/bearer.d.ts.map +1 -1
- package/dist/middleware/bearer.js +36 -6
- package/dist/middleware/bearer.js.map +1 -1
- package/dist/middleware/scope.d.ts +12 -2
- package/dist/middleware/scope.d.ts.map +1 -1
- package/dist/middleware/scope.js +46 -2
- package/dist/middleware/scope.js.map +1 -1
- package/dist/models/AccessToken.d.ts +32 -0
- package/dist/models/AccessToken.d.ts.map +1 -1
- package/dist/models/AccessToken.js +63 -3
- package/dist/models/AccessToken.js.map +1 -1
- package/dist/models/AuthCode.d.ts +16 -0
- package/dist/models/AuthCode.d.ts.map +1 -1
- package/dist/models/AuthCode.js +17 -1
- package/dist/models/AuthCode.js.map +1 -1
- package/dist/models/DeviceCode.d.ts +12 -2
- package/dist/models/DeviceCode.d.ts.map +1 -1
- package/dist/models/DeviceCode.js +7 -1
- package/dist/models/DeviceCode.js.map +1 -1
- package/dist/models/OAuthClient.d.ts +4 -0
- package/dist/models/OAuthClient.d.ts.map +1 -1
- package/dist/models/OAuthClient.js +13 -1
- package/dist/models/OAuthClient.js.map +1 -1
- package/dist/models/RefreshToken.d.ts +11 -0
- package/dist/models/RefreshToken.d.ts.map +1 -1
- package/dist/models/RefreshToken.js +12 -2
- package/dist/models/RefreshToken.js.map +1 -1
- package/dist/models/helpers.d.ts +6 -0
- package/dist/models/helpers.d.ts.map +1 -1
- package/dist/models/helpers.js +15 -2
- package/dist/models/helpers.js.map +1 -1
- package/dist/opaque-token.d.ts +32 -0
- package/dist/opaque-token.d.ts.map +1 -0
- package/dist/opaque-token.js +38 -0
- package/dist/opaque-token.js.map +1 -0
- package/dist/personal-access-tokens.d.ts.map +1 -1
- package/dist/personal-access-tokens.js +48 -10
- package/dist/personal-access-tokens.js.map +1 -1
- package/dist/routes.d.ts +149 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +279 -41
- package/dist/routes.js.map +1 -1
- package/dist/token.d.ts +80 -4
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +97 -13
- package/dist/token.js.map +1 -1
- package/package.json +5 -5
- package/schema/passport.prisma +29 -9
package/dist/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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.log(`
|
|
76
|
-
console.log(`
|
|
77
|
-
console.log(`
|
|
78
|
-
if (
|
|
79
|
-
console.log(`
|
|
80
|
-
console.log(`
|
|
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
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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:',
|
|
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":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAExD,6DAA6D;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAGxC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAExD,6DAA6D;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAGxC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAEnD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAE5E,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEnE,SAAS;AACT,OAAO,EACL,WAAW,EACX,4BAA4B,EAC5B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,mBAAmB,CAAA;AAY1B,yBAAyB;AACzB,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAGrF,SAAS;AACT,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAuC1G,6DAA6D;AAE7D,MAAM,OAAO,gBAAiB,SAAQ,eAAe;IACnD,QAAQ,KAAU,CAAC;IAEnB,KAAK,CAAC,IAAI;QACR,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;QAElD,MAAM,GAAG,GAAG,MAAM,CAAiB,UAAU,CAAC,CAAA;QAE9C,iBAAiB;QACjB,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YACpC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;QACjD,CAAC;aAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACvB,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACpC,CAAC;QAED,kEAAkE;QAClE,wEAAwE;QACxE,wEAAwE;QACxE,qEAAqE;QACrE,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC;YACtC,OAAO,CAAC,IAAI,CACV,iDAAiD,QAAQ,CAAC,OAAO,EAAE,+BAA+B;gBAClG,kEAAkE;gBAClE,kHAAkH,CACnH,CAAA;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,GAAG,CAAC,cAAc;YAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QACnE,IAAI,GAAG,CAAC,qBAAqB;YAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;QACxF,IAAI,GAAG,CAAC,4BAA4B;YAAE,QAAQ,CAAC,4BAA4B,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAA;QAE7G,mBAAmB;QACnB,IAAI,GAAG,CAAC,MAAM;YAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAE9C,2DAA2D;QAC3D,IAAI,GAAG,CAAC,MAAM;YAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAE9C,wEAAwE;QACxE,IAAI,GAAG,CAAC,iBAAiB,KAAK,SAAS;YAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;QAE1F,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAEvC,mEAAmE;QACnE,yEAAyE;QACzE,qEAAqE;QACrE,uEAAuE;QACvE,uEAAuE;QACvE,wEAAwE;QACxE,yEAAyE;QACzE,iBAAiB;QACjB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;QACvD,aAAa,CAAC,QAAQ,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;QACpD,aAAa,CAAC,QAAQ,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;QACnD,aAAa,CAAC,QAAQ,CAAC,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAA;QAC1D,aAAa,CAAC,QAAQ,CAAC,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAA;QACtD,aAAa,CAAC,QAAQ,CAAC,MAAM,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAA;QAExD,sEAAsE;QACtE,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,uEAAuE;QACvE,kEAAkE;QAClE,qDAAqD;QACrD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEjD,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,EAAE,IAAc,EAAE,EAAE;YACvD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YACtC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;YAC3D,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;YAC7F,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAA;YACpC,OAAO,CAAC,GAAG,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAA;YAC1C,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAA;YACzC,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;gBAC5C,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;gBACjD,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;gBAChD,IAAI,kBAAkB,EAAE,CAAC;oBACvB,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAA;oBACxE,OAAO,CAAC,GAAG,CAAC,OAAO,kBAAkB,EAAE,CAAC,CAAA;oBACxC,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAA;oBACjF,OAAO,CAAC,GAAG,CAAC,+EAA+E,CAAC,CAAA;gBAC9F,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC,WAAW,CAAC,+CAA+C,CAAC,CAAA;QAE/D,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,KAAK,EAAE,IAAc,EAAE,EAAE;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAA;YAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;YAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;YAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAA;YAEnD,yEAAyE;YACzE,sEAAsE;YACtE,qEAAqE;YACrE,8DAA8D;YAC9D,2DAA2D;YAC3D,kEAAkE;YAClE,qEAAqE;YACrE,mEAAmE;YACnE,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAA;gBAC7E,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAA;gBACpF,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAA;gBACjF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;gBACf,OAAO,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAA;gBACvF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;gBACf,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAA;gBAClE,OAAM;YACR,CAAC;YAED,MAAM,EAAE,YAAY,EAAE,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;YACtF,MAAM,UAAU,GAAG,uBAAuB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;YAC/D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC;gBAC5C,IAAI;gBACJ,YAAY,EAAE,CAAC,QAAQ,IAAI,CAAC,QAAQ;gBACpC,UAAU;aACX,CAAC,CAAA;YAEF,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAA;YACtC,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;YAC1C,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;YAC5C,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,EAAE,CAAC,CAAA;gBACvC,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAA;YACnE,CAAC;QACH,CAAC,CAAC,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAA;QAE3C,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;YAC3D,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAA;YAClC,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,WAAW,CAAA;YAChG,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,6BAA6B,CAAC,CAAA;YAC3D,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;YACzD,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAA;YAC1D,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;YACtD,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAC,WAAW,CAAC,sCAAsC,CAAC,CAAA;QAEtD,0CAA0C;QAC1C,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;QAC/D,iBAAiB,CAAC;YAChB,OAAO,EAAM,sBAAsB;YACnC,WAAW,EAAE,kCAAkC;YAC/C,KAAK,EAAQ,gCAAgC;YAC7C,SAAS,EAAI,aAAa;YAC1B,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC;;wBAEH,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE;;;;;;;;;;CAUrE;SACI,CAAC,CAAA;IACJ,CAAC;CACF"}
|
|
@@ -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;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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"}
|
package/dist/middleware/scope.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Middleware that requires
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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;
|
|
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"}
|