@xbg.solutions/utils-token-handler 1.0.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/lib/firebase-adapter.d.ts +46 -0
- package/lib/firebase-adapter.d.ts.map +1 -0
- package/lib/firebase-adapter.js +207 -0
- package/lib/firebase-adapter.js.map +1 -0
- package/lib/firestore-database-adapter.d.ts +46 -0
- package/lib/firestore-database-adapter.d.ts.map +1 -0
- package/lib/firestore-database-adapter.js +118 -0
- package/lib/firestore-database-adapter.js.map +1 -0
- package/lib/generic-token-handler.d.ts +68 -0
- package/lib/generic-token-handler.d.ts.map +1 -0
- package/lib/generic-token-handler.js +176 -0
- package/lib/generic-token-handler.js.map +1 -0
- package/lib/index.d.ts +71 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +109 -0
- package/lib/index.js.map +1 -0
- package/lib/token-blacklist-manager.d.ts +78 -0
- package/lib/token-blacklist-manager.d.ts.map +1 -0
- package/lib/token-blacklist-manager.js +174 -0
- package/lib/token-blacklist-manager.js.map +1 -0
- package/lib/token-types.d.ts +239 -0
- package/lib/token-types.d.ts.map +1 -0
- package/lib/token-types.js +20 -0
- package/lib/token-types.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generic Token Handler
|
|
4
|
+
* Platform-agnostic token handling with configurable auth providers
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TokenHandler = void 0;
|
|
8
|
+
exports.createTokenHandler = createTokenHandler;
|
|
9
|
+
const token_types_1 = require("./token-types");
|
|
10
|
+
const token_blacklist_manager_1 = require("./token-blacklist-manager");
|
|
11
|
+
class TokenHandler {
|
|
12
|
+
constructor(config, adapter) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.adapter = adapter;
|
|
15
|
+
this.blacklistManager = new token_blacklist_manager_1.TokenBlacklistManager(this.config.database, this.config.blacklist);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Verify and unpack raw token string
|
|
19
|
+
* Returns normalized token if valid, or error details if invalid
|
|
20
|
+
*/
|
|
21
|
+
async verifyAndUnpack(rawToken, logger) {
|
|
22
|
+
logger.debug('TokenHandler: Starting token verification');
|
|
23
|
+
try {
|
|
24
|
+
// Step 1: Verify token with auth provider
|
|
25
|
+
const providerToken = await this.adapter.verifyToken(rawToken, logger);
|
|
26
|
+
logger.debug('TokenHandler: Token verified by provider', {
|
|
27
|
+
authUID: this.extractAuthUID(providerToken)
|
|
28
|
+
});
|
|
29
|
+
// Step 2: Check if token is individually blacklisted
|
|
30
|
+
const tokenIdentifier = await this.adapter.getTokenIdentifier(rawToken);
|
|
31
|
+
const isIndividuallyBlacklisted = await this.blacklistManager.isBlacklisted(tokenIdentifier, logger);
|
|
32
|
+
if (isIndividuallyBlacklisted) {
|
|
33
|
+
logger.warn('TokenHandler: Token is individually blacklisted', {
|
|
34
|
+
authUID: this.extractAuthUID(providerToken)
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
isValid: false,
|
|
38
|
+
isBlacklisted: true,
|
|
39
|
+
token: null,
|
|
40
|
+
error: token_types_1.TokenVerificationError.BLACKLISTED
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Step 3: Check if user has global token revocation
|
|
44
|
+
const authUID = this.extractAuthUID(providerToken);
|
|
45
|
+
const revocationTime = await this.blacklistManager.getUserTokenRevocationTime(authUID, logger);
|
|
46
|
+
if (revocationTime) {
|
|
47
|
+
const tokenIssuedAt = this.extractIssuedAt(providerToken);
|
|
48
|
+
const tokenIssuedDate = new Date(tokenIssuedAt * 1000);
|
|
49
|
+
if (tokenIssuedDate < revocationTime) {
|
|
50
|
+
logger.warn('TokenHandler: Token issued before global revocation', {
|
|
51
|
+
authUID,
|
|
52
|
+
tokenIssuedAt: tokenIssuedDate,
|
|
53
|
+
// Don't log revocation time for privacy
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
isValid: false,
|
|
57
|
+
isBlacklisted: true,
|
|
58
|
+
token: null,
|
|
59
|
+
error: token_types_1.TokenVerificationError.BLACKLISTED
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Step 4: Normalize token to platform-agnostic structure
|
|
64
|
+
const normalizedToken = this.adapter.normalizeToken(providerToken, this.config.customClaims);
|
|
65
|
+
logger.debug('TokenHandler: Token verified and normalized', {
|
|
66
|
+
authUID: normalizedToken.authUID,
|
|
67
|
+
userUID: normalizedToken.userUID,
|
|
68
|
+
issuer: normalizedToken.issuer
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
isValid: true,
|
|
72
|
+
isBlacklisted: false,
|
|
73
|
+
token: normalizedToken,
|
|
74
|
+
error: null
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
logger.warn('TokenHandler: Token verification failed', {
|
|
79
|
+
error: error.message
|
|
80
|
+
});
|
|
81
|
+
// Map provider errors to our error types
|
|
82
|
+
const verificationError = this.adapter.mapProviderError(error);
|
|
83
|
+
return {
|
|
84
|
+
isValid: false,
|
|
85
|
+
isBlacklisted: false,
|
|
86
|
+
token: null,
|
|
87
|
+
error: verificationError
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate token identifier for blacklist lookup
|
|
93
|
+
*/
|
|
94
|
+
async getTokenIdentifier(rawToken) {
|
|
95
|
+
return this.adapter.getTokenIdentifier(rawToken);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Sync custom claims to auth provider
|
|
99
|
+
*/
|
|
100
|
+
async syncCustomClaims(authUID, claims, logger) {
|
|
101
|
+
logger.debug('TokenHandler: Syncing custom claims', {
|
|
102
|
+
authUID,
|
|
103
|
+
provider: this.config.provider.type
|
|
104
|
+
});
|
|
105
|
+
await this.adapter.syncCustomClaims(authUID, claims, logger);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Revoke all tokens for a user at provider level
|
|
109
|
+
*/
|
|
110
|
+
async revokeUserTokens(authUID, logger) {
|
|
111
|
+
logger.info('TokenHandler: Revoking user tokens at provider level', {
|
|
112
|
+
authUID,
|
|
113
|
+
provider: this.config.provider.type
|
|
114
|
+
});
|
|
115
|
+
return this.adapter.revokeUserTokens(authUID, logger);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Blacklist individual token
|
|
119
|
+
*/
|
|
120
|
+
async blacklistToken(tokenIdentifier, authUID, reason, tokenExpiresAt, blacklistedBy, logger) {
|
|
121
|
+
return this.blacklistManager.blacklistToken(tokenIdentifier, authUID, reason, tokenExpiresAt, blacklistedBy, logger);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Blacklist all tokens for a user (global revocation)
|
|
125
|
+
*/
|
|
126
|
+
async blacklistAllUserTokens(authUID, reason, blacklistedBy, logger) {
|
|
127
|
+
return this.blacklistManager.blacklistAllUserTokens(authUID, reason, blacklistedBy, logger);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if token is blacklisted
|
|
131
|
+
*/
|
|
132
|
+
async isTokenBlacklisted(tokenIdentifier, logger) {
|
|
133
|
+
return this.blacklistManager.isBlacklisted(tokenIdentifier, logger);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get user's token revocation timestamp
|
|
137
|
+
*/
|
|
138
|
+
async getUserTokenRevocationTime(authUID, logger) {
|
|
139
|
+
return this.blacklistManager.getUserTokenRevocationTime(authUID, logger);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Cleanup expired blacklist entries
|
|
143
|
+
*/
|
|
144
|
+
async cleanupExpiredEntries(logger) {
|
|
145
|
+
return this.blacklistManager.cleanupExpiredEntries(logger);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get token handler configuration
|
|
149
|
+
*/
|
|
150
|
+
getConfig() {
|
|
151
|
+
return Object.assign({}, this.config);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Extract authUID from provider token
|
|
155
|
+
* Different providers may structure this differently
|
|
156
|
+
*/
|
|
157
|
+
extractAuthUID(providerToken) {
|
|
158
|
+
// Common patterns for different providers
|
|
159
|
+
return providerToken.uid || providerToken.sub || providerToken.user_id || '';
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Extract issued-at timestamp from provider token
|
|
163
|
+
* Different providers may structure this differently
|
|
164
|
+
*/
|
|
165
|
+
extractIssuedAt(providerToken) {
|
|
166
|
+
return providerToken.iat || providerToken.issued_at || Math.floor(Date.now() / 1000);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.TokenHandler = TokenHandler;
|
|
170
|
+
/**
|
|
171
|
+
* Factory function to create token handler with type safety
|
|
172
|
+
*/
|
|
173
|
+
function createTokenHandler(config, adapter) {
|
|
174
|
+
return new TokenHandler(config, adapter);
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=generic-token-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-token-handler.js","sourceRoot":"","sources":["../src/generic-token-handler.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Handler Utility - Barrel Export
|
|
3
|
+
* Portable, configurable token handling with auth provider abstraction
|
|
4
|
+
*/
|
|
5
|
+
export * from './token-types';
|
|
6
|
+
export * from './generic-token-handler';
|
|
7
|
+
export * from './token-blacklist-manager';
|
|
8
|
+
export * from './firebase-adapter';
|
|
9
|
+
export * from './firestore-database-adapter';
|
|
10
|
+
export { createTokenHandler } from './generic-token-handler';
|
|
11
|
+
export { createTokenBlacklistManager } from './token-blacklist-manager';
|
|
12
|
+
export { createFirebaseAuthAdapter } from './firebase-adapter';
|
|
13
|
+
export { createFirestoreTokenDatabase } from './firestore-database-adapter';
|
|
14
|
+
/**
|
|
15
|
+
* Quick-start factory for Firebase-based token handling
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const handler = createFirebaseTokenHandler({
|
|
20
|
+
* customClaims: {
|
|
21
|
+
* extract: (token) => ({ userID: token.userID }),
|
|
22
|
+
* defaults: { userID: null }
|
|
23
|
+
* },
|
|
24
|
+
* blacklist: {
|
|
25
|
+
* storage: { database: 'main', collection: 'blacklist' },
|
|
26
|
+
* retention: { cleanupRetentionDays: 30, globalRevocationRetentionDays: 30 },
|
|
27
|
+
* reasons: ['LOGOUT', 'PASSWORD_CHANGE']
|
|
28
|
+
* },
|
|
29
|
+
* database: firestoreInstance
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function createFirebaseTokenHandler<TCustomClaims = Record<string, any>>(config: {
|
|
34
|
+
customClaims: {
|
|
35
|
+
extract: (token: any) => TCustomClaims;
|
|
36
|
+
validate?: (claims: TCustomClaims) => boolean;
|
|
37
|
+
defaults: Partial<TCustomClaims>;
|
|
38
|
+
};
|
|
39
|
+
blacklist: {
|
|
40
|
+
storage: {
|
|
41
|
+
database: string;
|
|
42
|
+
collection: string;
|
|
43
|
+
};
|
|
44
|
+
retention: {
|
|
45
|
+
cleanupRetentionDays: number;
|
|
46
|
+
globalRevocationRetentionDays: number;
|
|
47
|
+
};
|
|
48
|
+
reasons: string[];
|
|
49
|
+
};
|
|
50
|
+
database: any;
|
|
51
|
+
}): any;
|
|
52
|
+
/**
|
|
53
|
+
* Quick-start factory for Auth0-based token handling
|
|
54
|
+
* Future implementation when Auth0 adapter is available
|
|
55
|
+
*/
|
|
56
|
+
export declare function createAuth0TokenHandler<_TCustomClaims = Record<string, any>>(_config: any): void;
|
|
57
|
+
/**
|
|
58
|
+
* Quick-start factory for Clerk-based token handling
|
|
59
|
+
* Future implementation when Clerk adapter is available
|
|
60
|
+
*/
|
|
61
|
+
export declare function createClerkTokenHandler<_TCustomClaims = Record<string, any>>(_config: any): void;
|
|
62
|
+
/**
|
|
63
|
+
* Version and metadata
|
|
64
|
+
*/
|
|
65
|
+
export declare const TOKEN_HANDLER_VERSION = "2.0.0";
|
|
66
|
+
export declare const SUPPORTED_PROVIDERS: readonly ["firebase"];
|
|
67
|
+
/**
|
|
68
|
+
* Utility function to validate token handler configuration
|
|
69
|
+
*/
|
|
70
|
+
export declare function validateTokenHandlerConfig(config: any): boolean;
|
|
71
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,eAAe,CAAC;AAG9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAG1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAE5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE;IACtF,YAAY,EAAE;QACZ,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,aAAa,CAAC;QACvC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;QAC9C,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;KAClC,CAAC;IACF,SAAS,EAAE;QACT,OAAO,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;QAClD,SAAS,EAAE;YAAE,oBAAoB,EAAE,MAAM,CAAC;YAAC,6BAA6B,EAAE,MAAM,CAAA;SAAE,CAAC;QACnF,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,QAAQ,EAAE,GAAG,CAAC;CACf,OAuBA;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,QAEzF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,QAEzF;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAC7C,eAAO,MAAM,mBAAmB,uBAAwB,CAAC;AAEzD;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,GAAG,GACV,OAAO,CAST"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Token Handler Utility - Barrel Export
|
|
4
|
+
* Portable, configurable token handling with auth provider abstraction
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.SUPPORTED_PROVIDERS = exports.TOKEN_HANDLER_VERSION = exports.createFirestoreTokenDatabase = exports.createFirebaseAuthAdapter = exports.createTokenBlacklistManager = exports.createTokenHandler = void 0;
|
|
22
|
+
exports.createFirebaseTokenHandler = createFirebaseTokenHandler;
|
|
23
|
+
exports.createAuth0TokenHandler = createAuth0TokenHandler;
|
|
24
|
+
exports.createClerkTokenHandler = createClerkTokenHandler;
|
|
25
|
+
exports.validateTokenHandlerConfig = validateTokenHandlerConfig;
|
|
26
|
+
// Core types and interfaces
|
|
27
|
+
__exportStar(require("./token-types"), exports);
|
|
28
|
+
// Generic implementations
|
|
29
|
+
__exportStar(require("./generic-token-handler"), exports);
|
|
30
|
+
__exportStar(require("./token-blacklist-manager"), exports);
|
|
31
|
+
// Adapters
|
|
32
|
+
__exportStar(require("./firebase-adapter"), exports);
|
|
33
|
+
__exportStar(require("./firestore-database-adapter"), exports);
|
|
34
|
+
// Factory functions for common configurations
|
|
35
|
+
var generic_token_handler_1 = require("./generic-token-handler");
|
|
36
|
+
Object.defineProperty(exports, "createTokenHandler", { enumerable: true, get: function () { return generic_token_handler_1.createTokenHandler; } });
|
|
37
|
+
var token_blacklist_manager_1 = require("./token-blacklist-manager");
|
|
38
|
+
Object.defineProperty(exports, "createTokenBlacklistManager", { enumerable: true, get: function () { return token_blacklist_manager_1.createTokenBlacklistManager; } });
|
|
39
|
+
var firebase_adapter_1 = require("./firebase-adapter");
|
|
40
|
+
Object.defineProperty(exports, "createFirebaseAuthAdapter", { enumerable: true, get: function () { return firebase_adapter_1.createFirebaseAuthAdapter; } });
|
|
41
|
+
var firestore_database_adapter_1 = require("./firestore-database-adapter");
|
|
42
|
+
Object.defineProperty(exports, "createFirestoreTokenDatabase", { enumerable: true, get: function () { return firestore_database_adapter_1.createFirestoreTokenDatabase; } });
|
|
43
|
+
/**
|
|
44
|
+
* Quick-start factory for Firebase-based token handling
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const handler = createFirebaseTokenHandler({
|
|
49
|
+
* customClaims: {
|
|
50
|
+
* extract: (token) => ({ userID: token.userID }),
|
|
51
|
+
* defaults: { userID: null }
|
|
52
|
+
* },
|
|
53
|
+
* blacklist: {
|
|
54
|
+
* storage: { database: 'main', collection: 'blacklist' },
|
|
55
|
+
* retention: { cleanupRetentionDays: 30, globalRevocationRetentionDays: 30 },
|
|
56
|
+
* reasons: ['LOGOUT', 'PASSWORD_CHANGE']
|
|
57
|
+
* },
|
|
58
|
+
* database: firestoreInstance
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
function createFirebaseTokenHandler(config) {
|
|
63
|
+
const { createTokenHandler } = require('./generic-token-handler');
|
|
64
|
+
const { createFirebaseAuthAdapter } = require('./adapters/firebase-auth-adapter');
|
|
65
|
+
const { createFirestoreTokenDatabase } = require('./adapters/firestore-database-adapter');
|
|
66
|
+
// Create database adapter
|
|
67
|
+
const tokenDatabase = createFirestoreTokenDatabase(config.database, config.blacklist.storage.collection);
|
|
68
|
+
// Create auth adapter
|
|
69
|
+
const authAdapter = createFirebaseAuthAdapter();
|
|
70
|
+
// Build complete configuration
|
|
71
|
+
const handlerConfig = {
|
|
72
|
+
customClaims: config.customClaims,
|
|
73
|
+
blacklist: config.blacklist,
|
|
74
|
+
provider: { type: 'firebase' },
|
|
75
|
+
database: tokenDatabase
|
|
76
|
+
};
|
|
77
|
+
return createTokenHandler(handlerConfig, authAdapter);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Quick-start factory for Auth0-based token handling
|
|
81
|
+
* Future implementation when Auth0 adapter is available
|
|
82
|
+
*/
|
|
83
|
+
function createAuth0TokenHandler(_config) {
|
|
84
|
+
throw new Error('Auth0 adapter not yet implemented. Use createFirebaseTokenHandler for now.');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Quick-start factory for Clerk-based token handling
|
|
88
|
+
* Future implementation when Clerk adapter is available
|
|
89
|
+
*/
|
|
90
|
+
function createClerkTokenHandler(_config) {
|
|
91
|
+
throw new Error('Clerk adapter not yet implemented. Use createFirebaseTokenHandler for now.');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Version and metadata
|
|
95
|
+
*/
|
|
96
|
+
exports.TOKEN_HANDLER_VERSION = '2.0.0';
|
|
97
|
+
exports.SUPPORTED_PROVIDERS = ['firebase'];
|
|
98
|
+
/**
|
|
99
|
+
* Utility function to validate token handler configuration
|
|
100
|
+
*/
|
|
101
|
+
function validateTokenHandlerConfig(config) {
|
|
102
|
+
return (config &&
|
|
103
|
+
typeof config === 'object' &&
|
|
104
|
+
config.customClaims &&
|
|
105
|
+
config.blacklist &&
|
|
106
|
+
config.provider &&
|
|
107
|
+
config.database);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;AAsCH,gEAmCC;AAMD,0DAEC;AAMD,0DAEC;AAWD,gEAWC;AA7GD,4BAA4B;AAC5B,gDAA8B;AAE9B,0BAA0B;AAC1B,0DAAwC;AACxC,4DAA0C;AAE1C,WAAW;AACX,qDAAmC;AACnC,+DAA6C;AAE7C,8CAA8C;AAC9C,iEAA6D;AAApD,2HAAA,kBAAkB,OAAA;AAC3B,qEAAwE;AAA/D,sIAAA,2BAA2B,OAAA;AACpC,uDAA+D;AAAtD,6HAAA,yBAAyB,OAAA;AAClC,2EAA4E;AAAnE,0IAAA,4BAA4B,OAAA;AAErC;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,0BAA0B,CAAsC,MAY/E;IACC,MAAM,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAClE,MAAM,EAAE,yBAAyB,EAAE,GAAG,OAAO,CAAC,kCAAkC,CAAC,CAAC;IAClF,MAAM,EAAE,4BAA4B,EAAE,GAAG,OAAO,CAAC,uCAAuC,CAAC,CAAC;IAE1F,0BAA0B;IAC1B,MAAM,aAAa,GAAG,4BAA4B,CAChD,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CACpC,CAAC;IAEF,sBAAsB;IACtB,MAAM,WAAW,GAAG,yBAAyB,EAAE,CAAC;IAEhD,+BAA+B;IAC/B,MAAM,aAAa,GAAG;QACpB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAmB,EAAE;QACvC,QAAQ,EAAE,aAAa;KACxB,CAAC;IAEF,OAAO,kBAAkB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,SAAgB,uBAAuB,CAAuC,OAAY;IACxF,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;AAChG,CAAC;AAED;;;GAGG;AACH,SAAgB,uBAAuB,CAAuC,OAAY;IACxF,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;AAChG,CAAC;AAED;;GAEG;AACU,QAAA,qBAAqB,GAAG,OAAO,CAAC;AAChC,QAAA,mBAAmB,GAAG,CAAC,UAAU,CAAU,CAAC;AAEzD;;GAEG;AACH,SAAgB,0BAA0B,CACxC,MAAW;IAEX,OAAO,CACL,MAAM;QACN,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,CAAC,YAAY;QACnB,MAAM,CAAC,SAAS;QAChB,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,QAAQ,CAChB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Blacklist Manager
|
|
3
|
+
* Generic token blacklist implementation with configurable database backend
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from '@xbg/utils-logger';
|
|
6
|
+
import { TokenBlacklistEntry, ITokenDatabase, BlacklistConfig } from './token-types';
|
|
7
|
+
export declare class TokenBlacklistManager {
|
|
8
|
+
private database;
|
|
9
|
+
private config;
|
|
10
|
+
constructor(database: ITokenDatabase, config: BlacklistConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Add token to blacklist
|
|
13
|
+
*
|
|
14
|
+
* @param tokenIdentifier - Token JTI or hash
|
|
15
|
+
* @param authUID - User who owned this token
|
|
16
|
+
* @param reason - Reason for blacklisting (must be in configured reasons)
|
|
17
|
+
* @param tokenExpiresAt - When token would naturally expire
|
|
18
|
+
* @param blacklistedBy - Optional userUID who triggered blacklist
|
|
19
|
+
* @param logger - Logger instance
|
|
20
|
+
*/
|
|
21
|
+
blacklistToken(tokenIdentifier: string, authUID: string, reason: string, tokenExpiresAt: Date, blacklistedBy: string | null, logger: Logger): Promise<TokenBlacklistEntry>;
|
|
22
|
+
/**
|
|
23
|
+
* Check if token is blacklisted
|
|
24
|
+
*
|
|
25
|
+
* @param tokenIdentifier - Token JTI or hash
|
|
26
|
+
* @param logger - Logger instance
|
|
27
|
+
* @returns true if blacklisted, false otherwise
|
|
28
|
+
*/
|
|
29
|
+
isBlacklisted(tokenIdentifier: string, logger: Logger): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Blacklist all tokens for a user (global revocation)
|
|
32
|
+
* Used when user logs out all sessions, changes password, or account deleted
|
|
33
|
+
*
|
|
34
|
+
* This creates a revocation timestamp. Token verification checks:
|
|
35
|
+
* is token issued before this timestamp?
|
|
36
|
+
*
|
|
37
|
+
* @param authUID - User's auth UID
|
|
38
|
+
* @param reason - Reason for blacklisting (must be in configured reasons)
|
|
39
|
+
* @param blacklistedBy - Optional userUID who triggered blacklist
|
|
40
|
+
* @param logger - Logger instance
|
|
41
|
+
*/
|
|
42
|
+
blacklistAllUserTokens(authUID: string, reason: string, blacklistedBy: string | null, logger: Logger): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if user has a global token revocation
|
|
45
|
+
* Returns the timestamp of revocation if exists
|
|
46
|
+
*
|
|
47
|
+
* @param authUID - User's auth UID
|
|
48
|
+
* @param logger - Logger instance
|
|
49
|
+
* @returns Date of revocation, or null if no global revocation
|
|
50
|
+
*/
|
|
51
|
+
getUserTokenRevocationTime(authUID: string, logger: Logger): Promise<Date | null>;
|
|
52
|
+
/**
|
|
53
|
+
* Cleanup expired blacklist entries
|
|
54
|
+
* Run via CRON job periodically
|
|
55
|
+
*
|
|
56
|
+
* @param logger - Logger instance
|
|
57
|
+
* @returns Number of entries deleted
|
|
58
|
+
*/
|
|
59
|
+
cleanupExpiredEntries(logger: Logger): Promise<number>;
|
|
60
|
+
/**
|
|
61
|
+
* Get blacklist configuration
|
|
62
|
+
*/
|
|
63
|
+
getConfig(): BlacklistConfig;
|
|
64
|
+
/**
|
|
65
|
+
* Validate that reason is allowed by configuration
|
|
66
|
+
*/
|
|
67
|
+
private validateReason;
|
|
68
|
+
/**
|
|
69
|
+
* Mask token identifier for logging (security)
|
|
70
|
+
* Shows first 10 characters + ...
|
|
71
|
+
*/
|
|
72
|
+
private maskTokenIdentifier;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Factory function to create blacklist manager
|
|
76
|
+
*/
|
|
77
|
+
export declare function createTokenBlacklistManager(database: ITokenDatabase, config: BlacklistConfig): TokenBlacklistManager;
|
|
78
|
+
//# sourceMappingURL=token-blacklist-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-blacklist-manager.d.ts","sourceRoot":"","sources":["../src/token-blacklist-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,eAAe,EAChB,MAAM,eAAe,CAAC;AAGvB,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;gBADN,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,eAAe;IAGjC;;;;;;;;;OASG;IACG,cAAc,CAClB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,IAAI,EACpB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,CAAC;IAiC/B;;;;;;OAMG;IACG,aAAa,CACjB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;IAenB;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAsBhB;;;;;;;OAOG;IACG,0BAA0B,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAgBvB;;;;;;OAMG;IACG,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB5D;;OAEG;IACH,SAAS,IAAI,eAAe;IAI5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAM5B;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,eAAe,GACtB,qBAAqB,CAEvB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Token Blacklist Manager
|
|
4
|
+
* Generic token blacklist implementation with configurable database backend
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TokenBlacklistManager = void 0;
|
|
8
|
+
exports.createTokenBlacklistManager = createTokenBlacklistManager;
|
|
9
|
+
const uuid_1 = require("uuid");
|
|
10
|
+
class TokenBlacklistManager {
|
|
11
|
+
constructor(database, config) {
|
|
12
|
+
this.database = database;
|
|
13
|
+
this.config = config;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Add token to blacklist
|
|
17
|
+
*
|
|
18
|
+
* @param tokenIdentifier - Token JTI or hash
|
|
19
|
+
* @param authUID - User who owned this token
|
|
20
|
+
* @param reason - Reason for blacklisting (must be in configured reasons)
|
|
21
|
+
* @param tokenExpiresAt - When token would naturally expire
|
|
22
|
+
* @param blacklistedBy - Optional userUID who triggered blacklist
|
|
23
|
+
* @param logger - Logger instance
|
|
24
|
+
*/
|
|
25
|
+
async blacklistToken(tokenIdentifier, authUID, reason, tokenExpiresAt, blacklistedBy, logger) {
|
|
26
|
+
// Validate reason against configured reasons
|
|
27
|
+
this.validateReason(reason, logger);
|
|
28
|
+
logger.debug('TokenBlacklistManager: Adding token to blacklist', {
|
|
29
|
+
tokenIdentifier: this.maskTokenIdentifier(tokenIdentifier),
|
|
30
|
+
authUID,
|
|
31
|
+
reason,
|
|
32
|
+
database: this.config.storage.database,
|
|
33
|
+
collection: this.config.storage.collection
|
|
34
|
+
});
|
|
35
|
+
const entry = {
|
|
36
|
+
blacklistEntryUID: (0, uuid_1.v4)(),
|
|
37
|
+
tokenJTI: tokenIdentifier,
|
|
38
|
+
authUID,
|
|
39
|
+
blacklistedAt: new Date(),
|
|
40
|
+
blacklistedBy,
|
|
41
|
+
reason,
|
|
42
|
+
expiresAt: tokenExpiresAt
|
|
43
|
+
};
|
|
44
|
+
await this.database.addBlacklistEntry(entry);
|
|
45
|
+
logger.info('TokenBlacklistManager: Token blacklisted successfully', {
|
|
46
|
+
blacklistEntryUID: entry.blacklistEntryUID,
|
|
47
|
+
authUID,
|
|
48
|
+
reason
|
|
49
|
+
});
|
|
50
|
+
return entry;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if token is blacklisted
|
|
54
|
+
*
|
|
55
|
+
* @param tokenIdentifier - Token JTI or hash
|
|
56
|
+
* @param logger - Logger instance
|
|
57
|
+
* @returns true if blacklisted, false otherwise
|
|
58
|
+
*/
|
|
59
|
+
async isBlacklisted(tokenIdentifier, logger) {
|
|
60
|
+
logger.debug('TokenBlacklistManager: Checking if token is blacklisted', {
|
|
61
|
+
tokenIdentifier: this.maskTokenIdentifier(tokenIdentifier)
|
|
62
|
+
});
|
|
63
|
+
const isBlacklisted = await this.database.isTokenBlacklisted(tokenIdentifier);
|
|
64
|
+
logger.debug('TokenBlacklistManager: Blacklist check result', {
|
|
65
|
+
tokenIdentifier: this.maskTokenIdentifier(tokenIdentifier),
|
|
66
|
+
isBlacklisted
|
|
67
|
+
});
|
|
68
|
+
return isBlacklisted;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Blacklist all tokens for a user (global revocation)
|
|
72
|
+
* Used when user logs out all sessions, changes password, or account deleted
|
|
73
|
+
*
|
|
74
|
+
* This creates a revocation timestamp. Token verification checks:
|
|
75
|
+
* is token issued before this timestamp?
|
|
76
|
+
*
|
|
77
|
+
* @param authUID - User's auth UID
|
|
78
|
+
* @param reason - Reason for blacklisting (must be in configured reasons)
|
|
79
|
+
* @param blacklistedBy - Optional userUID who triggered blacklist
|
|
80
|
+
* @param logger - Logger instance
|
|
81
|
+
*/
|
|
82
|
+
async blacklistAllUserTokens(authUID, reason, blacklistedBy, logger) {
|
|
83
|
+
// Validate reason against configured reasons
|
|
84
|
+
this.validateReason(reason, logger);
|
|
85
|
+
logger.info('TokenBlacklistManager: Blacklisting all tokens for user', {
|
|
86
|
+
authUID,
|
|
87
|
+
reason
|
|
88
|
+
});
|
|
89
|
+
const expiresAt = new Date(Date.now() + this.config.retention.globalRevocationRetentionDays * 24 * 60 * 60 * 1000);
|
|
90
|
+
await this.database.addUserRevocation(authUID, reason, blacklistedBy, expiresAt);
|
|
91
|
+
logger.info('TokenBlacklistManager: All user tokens blacklisted', {
|
|
92
|
+
authUID,
|
|
93
|
+
reason,
|
|
94
|
+
expiresAt
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if user has a global token revocation
|
|
99
|
+
* Returns the timestamp of revocation if exists
|
|
100
|
+
*
|
|
101
|
+
* @param authUID - User's auth UID
|
|
102
|
+
* @param logger - Logger instance
|
|
103
|
+
* @returns Date of revocation, or null if no global revocation
|
|
104
|
+
*/
|
|
105
|
+
async getUserTokenRevocationTime(authUID, logger) {
|
|
106
|
+
logger.debug('TokenBlacklistManager: Checking user token revocation', {
|
|
107
|
+
authUID
|
|
108
|
+
});
|
|
109
|
+
const revocationTime = await this.database.getUserRevocationTime(authUID);
|
|
110
|
+
logger.debug('TokenBlacklistManager: User revocation check result', {
|
|
111
|
+
authUID,
|
|
112
|
+
hasRevocation: revocationTime !== null,
|
|
113
|
+
// Don't log the actual timestamp for privacy
|
|
114
|
+
});
|
|
115
|
+
return revocationTime;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Cleanup expired blacklist entries
|
|
119
|
+
* Run via CRON job periodically
|
|
120
|
+
*
|
|
121
|
+
* @param logger - Logger instance
|
|
122
|
+
* @returns Number of entries deleted
|
|
123
|
+
*/
|
|
124
|
+
async cleanupExpiredEntries(logger) {
|
|
125
|
+
logger.info('TokenBlacklistManager: Starting cleanup of expired entries', {
|
|
126
|
+
database: this.config.storage.database,
|
|
127
|
+
collection: this.config.storage.collection
|
|
128
|
+
});
|
|
129
|
+
const deletedCount = await this.database.cleanupExpiredEntries();
|
|
130
|
+
logger.info('TokenBlacklistManager: Cleanup completed', {
|
|
131
|
+
deletedCount,
|
|
132
|
+
database: this.config.storage.database,
|
|
133
|
+
collection: this.config.storage.collection
|
|
134
|
+
});
|
|
135
|
+
return deletedCount;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get blacklist configuration
|
|
139
|
+
*/
|
|
140
|
+
getConfig() {
|
|
141
|
+
return Object.assign({}, this.config);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Validate that reason is allowed by configuration
|
|
145
|
+
*/
|
|
146
|
+
validateReason(reason, logger) {
|
|
147
|
+
if (!this.config.reasons.includes(reason)) {
|
|
148
|
+
const error = new Error(`Invalid blacklist reason: ${reason}. Allowed reasons: ${this.config.reasons.join(', ')}`);
|
|
149
|
+
logger.error('TokenBlacklistManager: Invalid blacklist reason', error, {
|
|
150
|
+
providedReason: reason,
|
|
151
|
+
allowedReasons: this.config.reasons
|
|
152
|
+
});
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Mask token identifier for logging (security)
|
|
158
|
+
* Shows first 10 characters + ...
|
|
159
|
+
*/
|
|
160
|
+
maskTokenIdentifier(tokenIdentifier) {
|
|
161
|
+
if (tokenIdentifier.length <= 10) {
|
|
162
|
+
return tokenIdentifier;
|
|
163
|
+
}
|
|
164
|
+
return tokenIdentifier.substring(0, 10) + '...';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.TokenBlacklistManager = TokenBlacklistManager;
|
|
168
|
+
/**
|
|
169
|
+
* Factory function to create blacklist manager
|
|
170
|
+
*/
|
|
171
|
+
function createTokenBlacklistManager(database, config) {
|
|
172
|
+
return new TokenBlacklistManager(database, config);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=token-blacklist-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-blacklist-manager.js","sourceRoot":"","sources":["../src/token-blacklist-manager.ts"],"names":[],"mappings":"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"}
|