@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
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { Passport } from '../Passport.js';
|
|
2
2
|
import { clientHelpers, deviceCodeHelpers } from '../models/helpers.js';
|
|
3
|
+
import { hashDeviceSecret } from '../device-code-secret.js';
|
|
3
4
|
import { issueTokens } from './issue-tokens.js';
|
|
4
|
-
import { OAuthError } from './authorization-code.js';
|
|
5
|
+
import { OAuthError, validateScopes } from './authorization-code.js';
|
|
6
|
+
/**
|
|
7
|
+
* Initial polling interval for new device-code rows (RFC 8628 §3.5).
|
|
8
|
+
* Server escalates by 5s on each `slow_down` response, capped at
|
|
9
|
+
* `Passport.deviceMaxIntervalSeconds()` (default 60). RFC 8628 §3.5 doesn't
|
|
10
|
+
* specify a cap; we add one to keep degenerate clients from pushing the
|
|
11
|
+
* interval to absurd values, with the cap exposed to the operator so a
|
|
12
|
+
* niche flow (machine-only daemons, integration tests) can override it.
|
|
13
|
+
*/
|
|
14
|
+
const INITIAL_INTERVAL_SECONDS = 5;
|
|
5
15
|
/**
|
|
6
16
|
* Step 1: Device requests authorization codes.
|
|
7
17
|
* Returns device_code + user_code for the user to enter.
|
|
@@ -16,18 +26,27 @@ export async function requestDeviceCode(params) {
|
|
|
16
26
|
if (!clientHelpers.hasGrantType(client, 'urn:ietf:params:oauth:grant-type:device_code')) {
|
|
17
27
|
throw new OAuthError('unauthorized_client', 'Client is not authorized for device authorization grant.');
|
|
18
28
|
}
|
|
29
|
+
const scopes = params.scope ? params.scope.split(' ').filter(Boolean) : [];
|
|
30
|
+
validateScopes(client, scopes);
|
|
19
31
|
const { randomBytes } = await import('node:crypto');
|
|
20
32
|
const deviceCode = randomBytes(32).toString('hex');
|
|
21
33
|
const userCode = await generateUserCode();
|
|
22
|
-
const scopes = params.scope ? params.scope.split(' ').filter(Boolean) : [];
|
|
23
34
|
const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes
|
|
35
|
+
// Hash both codes at rest (M4 / RFC 8628 §6.1) — a DB read leak should
|
|
36
|
+
// not yield usable codes. The plaintext is returned to the client below
|
|
37
|
+
// and never persisted.
|
|
38
|
+
const [deviceCodeHash, userCodeHash] = await Promise.all([
|
|
39
|
+
hashDeviceSecret(deviceCode),
|
|
40
|
+
hashDeviceSecret(userCode),
|
|
41
|
+
]);
|
|
24
42
|
await DeviceCodeCls.create({
|
|
25
43
|
clientId: params.clientId,
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
deviceCodeHash,
|
|
45
|
+
userCodeHash,
|
|
28
46
|
scopes: JSON.stringify(scopes),
|
|
29
47
|
userId: null,
|
|
30
48
|
approved: null,
|
|
49
|
+
interval: INITIAL_INTERVAL_SECONDS,
|
|
31
50
|
expiresAt,
|
|
32
51
|
lastPolledAt: null,
|
|
33
52
|
});
|
|
@@ -37,7 +56,7 @@ export async function requestDeviceCode(params) {
|
|
|
37
56
|
verification_uri: params.verificationUri,
|
|
38
57
|
verification_uri_complete: `${params.verificationUri}?user_code=${userCode}`,
|
|
39
58
|
expires_in: 15 * 60, // 15 minutes in seconds
|
|
40
|
-
interval:
|
|
59
|
+
interval: INITIAL_INTERVAL_SECONDS,
|
|
41
60
|
};
|
|
42
61
|
}
|
|
43
62
|
// ─── User Approval ────────────────────────────────────────
|
|
@@ -46,7 +65,11 @@ export async function requestDeviceCode(params) {
|
|
|
46
65
|
*/
|
|
47
66
|
export async function approveDeviceCode(userCode, userId, approved) {
|
|
48
67
|
const DeviceCodeCls = await Passport.deviceCodeModel();
|
|
49
|
-
|
|
68
|
+
// M4 — look up by hash, not the plaintext the user typed. Same lookup
|
|
69
|
+
// surface an attacker would attempt against; the hash makes the column
|
|
70
|
+
// useless to an attacker who got a DB read.
|
|
71
|
+
const userCodeHash = await hashDeviceSecret(userCode);
|
|
72
|
+
const device = await DeviceCodeCls.where('userCodeHash', userCodeHash).first();
|
|
50
73
|
if (!device) {
|
|
51
74
|
throw new OAuthError('invalid_request', 'Device code not found.');
|
|
52
75
|
}
|
|
@@ -69,7 +92,9 @@ export async function pollDeviceCode(params) {
|
|
|
69
92
|
throw new OAuthError('unsupported_grant_type', 'Expected grant_type=urn:ietf:params:oauth:grant-type:device_code.');
|
|
70
93
|
}
|
|
71
94
|
const DeviceCodeCls = await Passport.deviceCodeModel();
|
|
72
|
-
|
|
95
|
+
// M4 — hash the supplied plaintext and look up by hash.
|
|
96
|
+
const deviceCodeHash = await hashDeviceSecret(params.deviceCode);
|
|
97
|
+
const device = await DeviceCodeCls.where('deviceCodeHash', deviceCodeHash).first();
|
|
73
98
|
if (!device) {
|
|
74
99
|
throw new OAuthError('invalid_grant', 'Device code not found.');
|
|
75
100
|
}
|
|
@@ -79,11 +104,17 @@ export async function pollDeviceCode(params) {
|
|
|
79
104
|
if (deviceCodeHelpers.isExpired(device)) {
|
|
80
105
|
return { status: 'expired_token' };
|
|
81
106
|
}
|
|
82
|
-
// Rate limiting
|
|
107
|
+
// Rate limiting (RFC 8628 §3.5). Enforce against the per-row `interval`
|
|
108
|
+
// (defaults to 5s, escalates by 5s per slow_down, capped at 60s). Persist
|
|
109
|
+
// the new interval so subsequent polls see the escalated value.
|
|
83
110
|
if (device.lastPolledAt) {
|
|
84
111
|
const elapsed = Date.now() - new Date(device.lastPolledAt).getTime();
|
|
85
|
-
if (elapsed <
|
|
86
|
-
|
|
112
|
+
if (elapsed < device.interval * 1000) {
|
|
113
|
+
const nextInterval = Math.min(device.interval + 5, Passport.deviceMaxIntervalSeconds());
|
|
114
|
+
if (nextInterval !== device.interval) {
|
|
115
|
+
await DeviceCodeCls.update(device.id, { interval: nextInterval });
|
|
116
|
+
}
|
|
117
|
+
return { status: 'slow_down', interval: nextInterval };
|
|
87
118
|
}
|
|
88
119
|
}
|
|
89
120
|
// Update last polled time
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-code.js","sourceRoot":"","sources":["../../src/grants/device-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGzC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,EAAE,WAAW,EAAqB,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"device-code.js","sourceRoot":"","sources":["../../src/grants/device-code.ts"],"names":[],"mappings":"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"}
|
package/dist/grants/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { issueTokens } from './issue-tokens.js';
|
|
2
2
|
export type { IssuedTokens } from './issue-tokens.js';
|
|
3
|
-
export { validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, OAuthError, } from './authorization-code.js';
|
|
3
|
+
export { validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, validateScopes, OAuthError, } from './authorization-code.js';
|
|
4
4
|
export type { AuthorizationRequest, ValidatedAuthRequest, TokenExchangeRequest, } from './authorization-code.js';
|
|
5
5
|
export { clientCredentialsGrant } from './client-credentials.js';
|
|
6
6
|
export type { ClientCredentialsRequest } from './client-credentials.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EACL,4BAA4B,EAC5B,aAAa,EACb,gBAAgB,EAChB,UAAU,GACX,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAChE,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAEvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAE7D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EACL,4BAA4B,EAC5B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,UAAU,GACX,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAChE,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAEvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAE7D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,kBAAkB,CAAA"}
|
package/dist/grants/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { issueTokens } from './issue-tokens.js';
|
|
2
|
-
export { validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, OAuthError, } from './authorization-code.js';
|
|
2
|
+
export { validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, validateScopes, OAuthError, } from './authorization-code.js';
|
|
3
3
|
export { clientCredentialsGrant } from './client-credentials.js';
|
|
4
4
|
export { refreshTokenGrant } from './refresh-token.js';
|
|
5
5
|
export { requestDeviceCode, approveDeviceCode, pollDeviceCode, } from './device-code.js';
|
package/dist/grants/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/grants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAG/C,OAAO,EACL,4BAA4B,EAC5B,aAAa,EACb,gBAAgB,EAChB,UAAU,GACX,MAAM,yBAAyB,CAAA;AAOhC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAGhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/grants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAG/C,OAAO,EACL,4BAA4B,EAC5B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,UAAU,GACX,MAAM,yBAAyB,CAAA;AAOhC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAGhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA"}
|
|
@@ -6,6 +6,13 @@ export interface IssuedTokens {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Issue an access token (+ optional refresh token) and persist to DB.
|
|
9
|
+
*
|
|
10
|
+
* `familyId` ties a refresh token to its rotation chain. On the first
|
|
11
|
+
* refresh-emitting grant for a session (auth-code, device-code, password)
|
|
12
|
+
* the caller leaves it undefined and a fresh family identifier is
|
|
13
|
+
* generated. On subsequent rotations the refresh-token grant passes the
|
|
14
|
+
* existing familyId through, so reuse-detection in `refreshTokenGrant`
|
|
15
|
+
* can revoke the entire chain in a single query (RFC 6819 §5.2.2.3).
|
|
9
16
|
*/
|
|
10
17
|
export declare function issueTokens(opts: {
|
|
11
18
|
userId: string | null;
|
|
@@ -14,5 +21,7 @@ export declare function issueTokens(opts: {
|
|
|
14
21
|
includeRefresh?: boolean;
|
|
15
22
|
/** Override access token lifetime in ms */
|
|
16
23
|
lifetime?: number;
|
|
24
|
+
/** Existing rotation-family id to copy onto the new refresh token. */
|
|
25
|
+
familyId?: string | null;
|
|
17
26
|
}): Promise<IssuedTokens>;
|
|
18
27
|
//# sourceMappingURL=issue-tokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-tokens.d.ts","sourceRoot":"","sources":["../../src/grants/issue-tokens.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAG,MAAM,CAAA;IACrB,UAAU,EAAK,QAAQ,CAAA;IACvB,UAAU,EAAK,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED
|
|
1
|
+
{"version":3,"file":"issue-tokens.d.ts","sourceRoot":"","sources":["../../src/grants/issue-tokens.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAG,MAAM,CAAA;IACrB,UAAU,EAAK,QAAQ,CAAA;IACvB,UAAU,EAAK,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,MAAM,EAAQ,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAM,MAAM,CAAA;IACpB,MAAM,EAAQ,MAAM,EAAE,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,EAAK,MAAM,CAAA;IACpB,sEAAsE;IACtE,QAAQ,CAAC,EAAK,MAAM,GAAG,IAAI,CAAA;CAC5B,GAAG,OAAO,CAAC,YAAY,CAAC,CAgExB"}
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { Passport } from '../Passport.js';
|
|
2
2
|
import { createToken } from '../token.js';
|
|
3
|
+
import { hashOpaqueToken, newOpaqueToken } from '../opaque-token.js';
|
|
3
4
|
/**
|
|
4
5
|
* Issue an access token (+ optional refresh token) and persist to DB.
|
|
6
|
+
*
|
|
7
|
+
* `familyId` ties a refresh token to its rotation chain. On the first
|
|
8
|
+
* refresh-emitting grant for a session (auth-code, device-code, password)
|
|
9
|
+
* the caller leaves it undefined and a fresh family identifier is
|
|
10
|
+
* generated. On subsequent rotations the refresh-token grant passes the
|
|
11
|
+
* existing familyId through, so reuse-detection in `refreshTokenGrant`
|
|
12
|
+
* can revoke the entire chain in a single query (RFC 6819 §5.2.2.3).
|
|
5
13
|
*/
|
|
6
14
|
export async function issueTokens(opts) {
|
|
7
15
|
const lifetime = opts.lifetime ?? Passport.tokenLifetime();
|
|
8
|
-
|
|
16
|
+
// Single wall-clock snapshot for the entire issuance — `iat` (in JWT),
|
|
17
|
+
// `exp` (= expiresAt), `expires_in` (lifetime/1000), and the refresh
|
|
18
|
+
// token's `expiresAt` all derive from this instant so a downstream
|
|
19
|
+
// verifier never sees `iat + expires_in !== exp` (sub-second drift between
|
|
20
|
+
// independent `Date.now()` reads is otherwise possible across the
|
|
21
|
+
// intervening async DB writes + key load).
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
const expiresAt = new Date(now + lifetime);
|
|
9
24
|
const AccessTokenCls = await Passport.tokenModel();
|
|
10
25
|
const RefreshTokenCls = await Passport.refreshTokenModel();
|
|
11
26
|
// Create DB record
|
|
@@ -24,22 +39,41 @@ export async function issueTokens(opts) {
|
|
|
24
39
|
clientId: opts.clientId,
|
|
25
40
|
scopes: opts.scopes,
|
|
26
41
|
expiresAt,
|
|
42
|
+
iatMs: now,
|
|
27
43
|
});
|
|
28
44
|
const result = {
|
|
29
45
|
access_token: jwt,
|
|
30
46
|
token_type: 'Bearer',
|
|
31
47
|
expires_in: Math.floor(lifetime / 1000),
|
|
32
48
|
};
|
|
33
|
-
// Issue refresh token
|
|
49
|
+
// Issue refresh token. M5/P6: the plaintext returned to the client is a
|
|
50
|
+
// fresh CSPRNG opaque string; only its SHA-256 is persisted (`tokenHash`).
|
|
51
|
+
// The previous shape — `result.refresh_token = refreshRecord.id` — handed
|
|
52
|
+
// every active refresh token to anyone with `SELECT * ON oauth_refresh_tokens`
|
|
53
|
+
// privilege on the database.
|
|
34
54
|
if (opts.includeRefresh !== false) {
|
|
35
|
-
const refreshExpiresAt = new Date(
|
|
36
|
-
const
|
|
55
|
+
const refreshExpiresAt = new Date(now + Passport.refreshTokenLifetime());
|
|
56
|
+
const familyId = opts.familyId ?? await newFamilyId();
|
|
57
|
+
const refreshPlaintext = await newOpaqueToken();
|
|
58
|
+
const refreshHash = await hashOpaqueToken(refreshPlaintext);
|
|
59
|
+
await RefreshTokenCls.create({
|
|
37
60
|
accessTokenId: tokenId,
|
|
61
|
+
tokenHash: refreshHash,
|
|
62
|
+
familyId,
|
|
38
63
|
revoked: false,
|
|
39
64
|
expiresAt: refreshExpiresAt,
|
|
40
65
|
});
|
|
41
|
-
result.refresh_token =
|
|
66
|
+
result.refresh_token = refreshPlaintext;
|
|
42
67
|
}
|
|
43
68
|
return result;
|
|
44
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Generate an opaque rotation-family id. Lazy-loads `node:crypto` so the
|
|
72
|
+
* package stays importable from non-Node runtimes that don't issue tokens
|
|
73
|
+
* themselves (the caller will have already loaded crypto when it got here).
|
|
74
|
+
*/
|
|
75
|
+
async function newFamilyId() {
|
|
76
|
+
const { randomUUID } = await import('node:crypto');
|
|
77
|
+
return randomUUID();
|
|
78
|
+
}
|
|
45
79
|
//# sourceMappingURL=issue-tokens.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-tokens.js","sourceRoot":"","sources":["../../src/grants/issue-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"issue-tokens.js","sourceRoot":"","sources":["../../src/grants/issue-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AASpE;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IASjC;IACC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAA;IAC1D,uEAAuE;IACvE,qEAAqE;IACrE,mEAAmE;IACnE,2EAA2E;IAC3E,kEAAkE;IAClE,2CAA2C;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAA;IAE1C,MAAM,cAAc,GAAI,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAA;IACnD,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAA;IAE1D,mBAAmB;IACnB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC;QAC9C,MAAM,EAAK,IAAI,CAAC,MAAM;QACtB,QAAQ,EAAG,IAAI,CAAC,QAAQ;QACxB,MAAM,EAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QACtC,OAAO,EAAI,KAAK;QAChB,SAAS;KACiB,CAAgB,CAAA;IAE5C,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,CAAA;IAE9B,WAAW;IACX,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC;QAC5B,OAAO;QACP,MAAM,EAAI,IAAI,CAAC,MAAM;QACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,MAAM,EAAI,IAAI,CAAC,MAAM;QACrB,SAAS;QACT,KAAK,EAAK,GAAG;KACd,CAAC,CAAA;IAEF,MAAM,MAAM,GAAiB;QAC3B,YAAY,EAAE,GAAG;QACjB,UAAU,EAAI,QAAQ;QACtB,UAAU,EAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;KAC1C,CAAA;IAED,wEAAwE;IACxE,2EAA2E;IAC3E,0EAA0E;IAC1E,+EAA+E;IAC/E,6BAA6B;IAC7B,IAAI,IAAI,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;QAClC,MAAM,gBAAgB,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,oBAAoB,EAAE,CAAC,CAAA;QACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,WAAW,EAAE,CAAA;QACrD,MAAM,gBAAgB,GAAG,MAAM,cAAc,EAAE,CAAA;QAC/C,MAAM,WAAW,GAAQ,MAAM,eAAe,CAAC,gBAAgB,CAAC,CAAA;QAEhE,MAAM,eAAe,CAAC,MAAM,CAAC;YAC3B,aAAa,EAAE,OAAO;YACtB,SAAS,EAAM,WAAW;YAC1B,QAAQ;YACR,OAAO,EAAQ,KAAK;YACpB,SAAS,EAAM,gBAAgB;SACL,CAAC,CAAA;QAE7B,MAAM,CAAC,aAAa,GAAG,gBAAgB,CAAA;IACzC,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW;IACxB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAClD,OAAO,UAAU,EAAE,CAAA;AACrB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../src/grants/refresh-token.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../src/grants/refresh-token.ts"],"names":[],"mappings":"AAOA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGlE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAK,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAM,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAQ,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CA6F1F"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Passport } from '../Passport.js';
|
|
2
2
|
import { accessTokenHelpers, refreshTokenHelpers } from '../models/helpers.js';
|
|
3
|
+
import { verifyClientSecret } from '../client-secret.js';
|
|
4
|
+
import { hashOpaqueToken } from '../opaque-token.js';
|
|
3
5
|
import { issueTokens } from './issue-tokens.js';
|
|
4
6
|
import { OAuthError } from './authorization-code.js';
|
|
5
7
|
/**
|
|
@@ -23,18 +25,35 @@ export async function refreshTokenGrant(params) {
|
|
|
23
25
|
if (!params.clientSecret) {
|
|
24
26
|
throw new OAuthError('invalid_client', 'Client secret required.', 401);
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
// Schema allows `client.secret` to be null; explicit guard so a future
|
|
29
|
+
// refactor can't mask `secret = null` as authenticating. See
|
|
30
|
+
// `client-credentials.ts` for the longer-form rationale.
|
|
31
|
+
if (client.secret == null) {
|
|
32
|
+
throw new OAuthError('invalid_client', 'Confidential client has no secret on file.', 401);
|
|
33
|
+
}
|
|
34
|
+
if (!(await verifyClientSecret(params.clientSecret, client.secret))) {
|
|
29
35
|
throw new OAuthError('invalid_client', 'Invalid client secret.', 401);
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
|
-
// Find refresh token
|
|
33
|
-
|
|
38
|
+
// Find refresh token by hashed plaintext (M5/P6) — the row's `id` is no
|
|
39
|
+
// longer the bearer secret, so a DB read leak doesn't yield usable tokens.
|
|
40
|
+
// Pre-migration tokens (which used `id` as the plaintext) won't match
|
|
41
|
+
// because their hashed form was never persisted; affected sessions force-
|
|
42
|
+
// relogin on next refresh, same blast radius as RSA keypair rotation.
|
|
43
|
+
const refreshTokenHash = await hashOpaqueToken(params.refreshToken);
|
|
44
|
+
const refreshToken = await RefreshTokenCls.where('tokenHash', refreshTokenHash).first();
|
|
34
45
|
if (!refreshToken) {
|
|
35
46
|
throw new OAuthError('invalid_grant', 'Refresh token not found.');
|
|
36
47
|
}
|
|
37
48
|
if (refreshToken.revoked) {
|
|
49
|
+
// Reuse detected. RFC 6819 §5.2.2.3 / OAuth 2.0 BCP §4.14: revoke the
|
|
50
|
+
// entire family so a stolen+rotated refresh token can't keep living
|
|
51
|
+
// alongside the legitimate user's session. Legacy rows minted before
|
|
52
|
+
// the familyId column existed have null and are exempt during the
|
|
53
|
+
// migration window — same approach as the redirect_uri rollout.
|
|
54
|
+
if (refreshToken.familyId) {
|
|
55
|
+
await revokeFamily(RefreshTokenCls, AccessTokenCls, refreshToken.familyId);
|
|
56
|
+
}
|
|
38
57
|
throw new OAuthError('invalid_grant', 'Refresh token has been revoked.');
|
|
39
58
|
}
|
|
40
59
|
if (refreshTokenHelpers.isExpired(refreshToken)) {
|
|
@@ -59,15 +78,51 @@ export async function refreshTokenGrant(params) {
|
|
|
59
78
|
}
|
|
60
79
|
scopes = requested;
|
|
61
80
|
}
|
|
62
|
-
// Revoke old tokens
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
//
|
|
81
|
+
// Revoke old tokens. Goes through QueryBuilder.updateAll() — bypasses the
|
|
82
|
+
// mass-assignment filter (`revoked` is no longer in fillable on either
|
|
83
|
+
// model) and avoids paying for a second hydration round-trip per
|
|
84
|
+
// refresh.
|
|
85
|
+
await RefreshTokenCls.where('id', refreshToken.id).updateAll({ revoked: true });
|
|
86
|
+
await AccessTokenCls.where('id', accessToken.id).updateAll({ revoked: true });
|
|
87
|
+
// Issue new pair — propagate the existing familyId so the rotation chain
|
|
88
|
+
// is preserved. Legacy rows with null get a fresh family on next rotation.
|
|
66
89
|
return issueTokens({
|
|
67
90
|
userId: accessToken.userId,
|
|
68
91
|
clientId: params.clientId,
|
|
69
92
|
scopes,
|
|
70
93
|
includeRefresh: true,
|
|
94
|
+
familyId: refreshToken.familyId ?? null,
|
|
71
95
|
});
|
|
72
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Revoke every access + refresh token in a rotation family. Called on
|
|
99
|
+
* detected reuse of an already-revoked refresh token. Best-effort: ORM
|
|
100
|
+
* errors are not propagated to the caller because the outer flow is
|
|
101
|
+
* already going to throw `invalid_grant`. Failures here would only mask
|
|
102
|
+
* the security signal that prompted the family lookup.
|
|
103
|
+
*/
|
|
104
|
+
async function revokeFamily(RefreshTokenCls, AccessTokenCls, familyId) {
|
|
105
|
+
try {
|
|
106
|
+
// Two bulk QueryBuilder.updateAll() calls — one per table — replace
|
|
107
|
+
// the prior read-then-N+1-update loop. Each is idempotent: refresh
|
|
108
|
+
// tokens already revoked are filtered by the inner where, and access
|
|
109
|
+
// tokens scoped by family-membership via their refresh tokens'
|
|
110
|
+
// accessTokenId list. Bypasses the mass-assignment filter (`revoked`
|
|
111
|
+
// is no longer in fillable on either model).
|
|
112
|
+
const family = await RefreshTokenCls.where('familyId', familyId).get();
|
|
113
|
+
if (family.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
await RefreshTokenCls.where('familyId', familyId)
|
|
116
|
+
.where('revoked', false)
|
|
117
|
+
.updateAll({ revoked: true });
|
|
118
|
+
const accessTokenIds = family.map(rt => rt.accessTokenId);
|
|
119
|
+
// `Model.where(col, val)` is 2-arg only; operator overloads live on the
|
|
120
|
+
// QueryBuilder returned by `query()`. Use that to express IN(...).
|
|
121
|
+
await AccessTokenCls.query().where('id', 'IN', accessTokenIds)
|
|
122
|
+
.updateAll({ revoked: true });
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Swallow — the outer handler always throws invalid_grant on reuse.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
73
128
|
//# sourceMappingURL=refresh-token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh-token.js","sourceRoot":"","sources":["../../src/grants/refresh-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAIzC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAqB,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAUpD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAA2B;IACjE,IAAI,MAAM,CAAC,SAAS,KAAK,eAAe,EAAE,CAAC;QACzC,MAAM,IAAI,UAAU,CAAC,wBAAwB,EAAE,oCAAoC,CAAC,CAAA;IACtF,CAAC;IAED,MAAM,SAAS,GAAS,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAA;IACpD,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAA;IAC1D,MAAM,cAAc,GAAI,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAA;IAEnD,kBAAkB;IAClB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAwB,CAAA;IACzF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC9B,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAA;IAClE,CAAC;IAED,mDAAmD;IACnD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzB,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAA;QACxE,CAAC;QACD,
|
|
1
|
+
{"version":3,"file":"refresh-token.js","sourceRoot":"","sources":["../../src/grants/refresh-token.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constant-time string comparison.
|
|
3
|
+
*
|
|
4
|
+
* Used on every site that compares a hashed credential or a verifier:
|
|
5
|
+
* client secret hashes (hex), PKCE verifier ↔ challenge (base64url for
|
|
6
|
+
* S256, raw for plain). `===` / `!==` short-circuits on first mismatch,
|
|
7
|
+
* leaking timing on pathological inputs; `timingSafeEqual` runs in O(n)
|
|
8
|
+
* regardless of where the first mismatch falls.
|
|
9
|
+
*
|
|
10
|
+
* Returns `false` for any null/undefined input or length mismatch — both
|
|
11
|
+
* surface as authentication failures upstream, no need to throw.
|
|
12
|
+
*
|
|
13
|
+
* `node:crypto` is lazy-loaded so this module is safe to import from
|
|
14
|
+
* package entrypoints (matches the rest of @rudderjs/passport's lazy
|
|
15
|
+
* crypto pattern; Vite externalizes node:* and a top-level import crashes
|
|
16
|
+
* the browser).
|
|
17
|
+
*/
|
|
18
|
+
export declare function safeCompare(a: string | null | undefined, b: string | null | undefined): Promise<boolean>;
|
|
19
|
+
//# sourceMappingURL=safe-compare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-compare.d.ts","sourceRoot":"","sources":["../../src/grants/safe-compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9G"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constant-time string comparison.
|
|
3
|
+
*
|
|
4
|
+
* Used on every site that compares a hashed credential or a verifier:
|
|
5
|
+
* client secret hashes (hex), PKCE verifier ↔ challenge (base64url for
|
|
6
|
+
* S256, raw for plain). `===` / `!==` short-circuits on first mismatch,
|
|
7
|
+
* leaking timing on pathological inputs; `timingSafeEqual` runs in O(n)
|
|
8
|
+
* regardless of where the first mismatch falls.
|
|
9
|
+
*
|
|
10
|
+
* Returns `false` for any null/undefined input or length mismatch — both
|
|
11
|
+
* surface as authentication failures upstream, no need to throw.
|
|
12
|
+
*
|
|
13
|
+
* `node:crypto` is lazy-loaded so this module is safe to import from
|
|
14
|
+
* package entrypoints (matches the rest of @rudderjs/passport's lazy
|
|
15
|
+
* crypto pattern; Vite externalizes node:* and a top-level import crashes
|
|
16
|
+
* the browser).
|
|
17
|
+
*/
|
|
18
|
+
export async function safeCompare(a, b) {
|
|
19
|
+
if (a == null || b == null)
|
|
20
|
+
return false;
|
|
21
|
+
if (a.length !== b.length)
|
|
22
|
+
return false;
|
|
23
|
+
const { timingSafeEqual } = await import('node:crypto');
|
|
24
|
+
// UTF-8 bytes — works for any ASCII encoding (hex, base64url) and length
|
|
25
|
+
// checks above guarantee Buffer.byteLength matches for these inputs.
|
|
26
|
+
return timingSafeEqual(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8'));
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=safe-compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-compare.js","sourceRoot":"","sources":["../../src/grants/safe-compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,CAA4B,EAAE,CAA4B;IAC1F,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,KAAK,CAAA;IACxC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAG,OAAO,KAAK,CAAA;IACxC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IACvD,yEAAyE;IACzE,qEAAqE;IACrE,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AACxE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import { ServiceProvider } from '@rudderjs/core';
|
|
2
2
|
export { Passport } from './Passport.js';
|
|
3
3
|
export type { PassportScope, AuthorizationViewContext, AuthorizationViewFn } from './Passport.js';
|
|
4
|
-
export { createToken, verifyToken, decodeToken } from './token.js';
|
|
5
|
-
export type { JwtHeader, JwtPayload } from './token.js';
|
|
4
|
+
export { createToken, verifyToken, unsafeDecodeToken, decodeToken } from './token.js';
|
|
5
|
+
export type { JwtHeader, JwtPayload, VerifyTokenOptions } from './token.js';
|
|
6
6
|
export { OAuthClient } from './models/OAuthClient.js';
|
|
7
7
|
export { AccessToken } from './models/AccessToken.js';
|
|
8
8
|
export { RefreshToken } from './models/RefreshToken.js';
|
|
9
9
|
export { AuthCode } from './models/AuthCode.js';
|
|
10
10
|
export { DeviceCode } from './models/DeviceCode.js';
|
|
11
11
|
export { BearerMiddleware, RequireBearer } from './middleware/bearer.js';
|
|
12
|
-
export { scope } from './middleware/scope.js';
|
|
12
|
+
export { scope, scopeAny } from './middleware/scope.js';
|
|
13
13
|
export { generateKeys } from './commands/keys.js';
|
|
14
|
-
export { createClient } from './commands/client.js';
|
|
14
|
+
export { createClient, resolveClientGrantTypes } from './commands/client.js';
|
|
15
15
|
export type { CreateClientOpts } from './commands/client.js';
|
|
16
16
|
export { purgeTokens } from './commands/purge.js';
|
|
17
|
-
export {
|
|
17
|
+
export { hashClientSecret, verifyClientSecret } from './client-secret.js';
|
|
18
|
+
export { hashDeviceSecret } from './device-code-secret.js';
|
|
19
|
+
export { hashOpaqueToken, newOpaqueToken } from './opaque-token.js';
|
|
20
|
+
export { issueTokens, validateAuthorizationRequest, issueAuthCode, exchangeAuthCode, validateScopes, OAuthError, clientCredentialsGrant, refreshTokenGrant, requestDeviceCode, approveDeviceCode, pollDeviceCode, } from './grants/index.js';
|
|
18
21
|
export type { IssuedTokens, AuthorizationRequest, ValidatedAuthRequest, TokenExchangeRequest, ClientCredentialsRequest, RefreshTokenRequest, DeviceAuthorizationResponse, DevicePollResult, } from './grants/index.js';
|
|
19
22
|
export { HasApiTokens, resetPersonalAccessClient } from './personal-access-tokens.js';
|
|
20
23
|
export type { NewPersonalAccessToken } from './personal-access-tokens.js';
|
|
21
|
-
export { registerPassportRoutes } from './routes.js';
|
|
24
|
+
export { registerPassportRoutes, registerPassportWebRoutes, registerPassportApiRoutes } from './routes.js';
|
|
22
25
|
export type { PassportRouteOptions, PassportRouteGroup } from './routes.js';
|
|
23
26
|
export interface PassportConfig {
|
|
24
27
|
/** Directory where RSA keys are stored (default: 'storage') */
|
|
@@ -34,6 +37,24 @@ export interface PassportConfig {
|
|
|
34
37
|
personalAccessTokensExpireIn?: number;
|
|
35
38
|
/** OAuth scopes: { scopeId: 'description' } */
|
|
36
39
|
scopes?: Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* JWT issuer URL. When set, `createToken()` stamps it as the `iss` claim
|
|
42
|
+
* on every new access token, and `BearerMiddleware`/`RequireBearer` ask
|
|
43
|
+
* `verifyToken()` to reject tokens whose `iss` claim doesn't match.
|
|
44
|
+
* Tokens minted before this is configured carry no `iss` and pass
|
|
45
|
+
* verification (legacy migration window). Recommended once a deployment
|
|
46
|
+
* has more than one possible signer (multi-tenant, staging+prod sharing
|
|
47
|
+
* keys). RFC 8725 §3.10.
|
|
48
|
+
*/
|
|
49
|
+
issuer?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Maximum value (in seconds) the per-row `oauth_device_codes.interval`
|
|
52
|
+
* is allowed to grow to via repeated `slow_down` escalations (RFC 8628
|
|
53
|
+
* §3.5). Default 60. Floor is 5 (the initial interval); values below
|
|
54
|
+
* the floor are clamped. Raise for machine-only / no-human-in-the-loop
|
|
55
|
+
* device flows where misbehaving clients warrant aggressive back-off.
|
|
56
|
+
*/
|
|
57
|
+
deviceMaxInterval?: number;
|
|
37
58
|
}
|
|
38
59
|
export declare class PassportProvider extends ServiceProvider {
|
|
39
60
|
register(): void;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,gBAAgB,CAAA;AAIxD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAEjG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|