@prmichaelsen/firebase-admin-sdk-v8 2.0.2 → 2.0.5
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/README.md +40 -18
- package/dist/index.d.mts +62 -19
- package/dist/index.d.ts +62 -19
- package/dist/index.js +58 -20
- package/dist/index.mjs +55 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,28 +30,50 @@ npm install firebase-admin-sdk-v8
|
|
|
30
30
|
|
|
31
31
|
## 🚀 Quick Start
|
|
32
32
|
|
|
33
|
-
### 1.
|
|
33
|
+
### 1. Initialize the SDK
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
# Firebase Admin Service Account (JSON string) - REQUIRED
|
|
37
|
-
FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY='{"type":"service_account","project_id":"...","private_key":"...","client_email":"..."}'
|
|
35
|
+
**Option A: Cloudflare Workers / Edge Runtimes (Recommended)**
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
```typescript
|
|
38
|
+
import { initializeApp, verifyIdToken } from '@prmichaelsen/firebase-admin-sdk-v8';
|
|
39
|
+
|
|
40
|
+
export default {
|
|
41
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
42
|
+
// Initialize with env variables
|
|
43
|
+
initializeApp({
|
|
44
|
+
serviceAccount: env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY,
|
|
45
|
+
projectId: env.FIREBASE_PROJECT_ID
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Now use the SDK
|
|
49
|
+
const token = request.headers.get('authorization')?.split('Bearer ')[1];
|
|
50
|
+
const user = await verifyIdToken(token);
|
|
51
|
+
|
|
52
|
+
return new Response(JSON.stringify({ user }));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Option B: Node.js / Traditional Environments**
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { initializeApp } from '@prmichaelsen/firebase-admin-sdk-v8';
|
|
61
|
+
|
|
62
|
+
// Option 1: Explicit initialization
|
|
63
|
+
initializeApp({
|
|
64
|
+
serviceAccount: JSON.parse(process.env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY!),
|
|
65
|
+
projectId: process.env.FIREBASE_PROJECT_ID
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Option 2: Auto-detect from process.env (no initialization needed)
|
|
69
|
+
// The SDK will automatically use process.env if initializeApp() is not called
|
|
50
70
|
```
|
|
51
71
|
|
|
52
|
-
**
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
**Environment Variables (if not using initializeApp):**
|
|
73
|
+
```env
|
|
74
|
+
FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY='{"type":"service_account",...}'
|
|
75
|
+
FIREBASE_PROJECT_ID=your-project-id
|
|
76
|
+
```
|
|
55
77
|
|
|
56
78
|
### 2. Verify ID Tokens
|
|
57
79
|
|
package/dist/index.d.mts
CHANGED
|
@@ -175,6 +175,67 @@ interface BatchWriteResult {
|
|
|
175
175
|
}>;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Firebase Admin SDK v8 - Configuration
|
|
180
|
+
* Manages SDK configuration and credentials
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* SDK Configuration
|
|
185
|
+
*/
|
|
186
|
+
interface SDKConfig {
|
|
187
|
+
serviceAccount?: ServiceAccount | string;
|
|
188
|
+
projectId?: string;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Initialize the Firebase Admin SDK with configuration
|
|
192
|
+
* This is optional - the SDK will fall back to environment variables if not called
|
|
193
|
+
*
|
|
194
|
+
* @param config - SDK configuration
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* // Cloudflare Workers
|
|
199
|
+
* export default {
|
|
200
|
+
* async fetch(request, env) {
|
|
201
|
+
* initializeApp({
|
|
202
|
+
* serviceAccount: env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY,
|
|
203
|
+
* projectId: env.FIREBASE_PROJECT_ID
|
|
204
|
+
* });
|
|
205
|
+
* // ... use SDK
|
|
206
|
+
* }
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* // Node.js (optional - will use process.env by default)
|
|
213
|
+
* initializeApp({
|
|
214
|
+
* serviceAccount: JSON.parse(process.env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY),
|
|
215
|
+
* projectId: process.env.FIREBASE_PROJECT_ID
|
|
216
|
+
* });
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
declare function initializeApp(config: SDKConfig): void;
|
|
220
|
+
/**
|
|
221
|
+
* Get the current SDK configuration
|
|
222
|
+
*/
|
|
223
|
+
declare function getConfig(): SDKConfig;
|
|
224
|
+
/**
|
|
225
|
+
* Clear the SDK configuration (useful for testing)
|
|
226
|
+
*/
|
|
227
|
+
declare function clearConfig(): void;
|
|
228
|
+
/**
|
|
229
|
+
* Get service account from config or environment
|
|
230
|
+
* Priority: 1) globalConfig, 2) process.env
|
|
231
|
+
*/
|
|
232
|
+
declare function getServiceAccount(): ServiceAccount;
|
|
233
|
+
/**
|
|
234
|
+
* Get Firebase project ID from config or environment
|
|
235
|
+
* Priority: 1) globalConfig, 2) process.env
|
|
236
|
+
*/
|
|
237
|
+
declare function getProjectId(): string;
|
|
238
|
+
|
|
178
239
|
/**
|
|
179
240
|
* Firebase Admin SDK v8 - Authentication
|
|
180
241
|
* ID token verification supporting both Firebase v9 and v10 token formats
|
|
@@ -451,22 +512,4 @@ declare function getAdminAccessToken(): Promise<string>;
|
|
|
451
512
|
*/
|
|
452
513
|
declare function clearTokenCache(): void;
|
|
453
514
|
|
|
454
|
-
|
|
455
|
-
* Firebase Admin SDK v8 - Service Account Management
|
|
456
|
-
*/
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Get Firebase service account from environment variable
|
|
460
|
-
* @throws {Error} If FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY is not set
|
|
461
|
-
* @returns {ServiceAccount} Parsed service account credentials
|
|
462
|
-
*/
|
|
463
|
-
declare function getServiceAccount(): ServiceAccount;
|
|
464
|
-
/**
|
|
465
|
-
* Get Firebase project ID from environment
|
|
466
|
-
* Checks multiple possible environment variable names
|
|
467
|
-
* @throws {Error} If no project ID is found
|
|
468
|
-
* @returns {string} Firebase project ID
|
|
469
|
-
*/
|
|
470
|
-
declare function getProjectId(): string;
|
|
471
|
-
|
|
472
|
-
export { type BatchWrite, type BatchWriteResult, type DataObject, type DecodedIdToken, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FirestoreDocument, type FirestoreValue, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type TokenResponse, type UpdateOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearTokenCache, deleteDocument, getAdminAccessToken, getAuth, getDocument, getProjectId, getServiceAccount, getUserFromToken, queryDocuments, setDocument, updateDocument, verifyIdToken };
|
|
515
|
+
export { type BatchWrite, type BatchWriteResult, type DataObject, type DecodedIdToken, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FirestoreDocument, type FirestoreValue, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type TokenResponse, type UpdateOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearConfig, clearTokenCache, deleteDocument, getAdminAccessToken, getAuth, getConfig, getDocument, getProjectId, getServiceAccount, getUserFromToken, initializeApp, queryDocuments, setDocument, updateDocument, verifyIdToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -175,6 +175,67 @@ interface BatchWriteResult {
|
|
|
175
175
|
}>;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Firebase Admin SDK v8 - Configuration
|
|
180
|
+
* Manages SDK configuration and credentials
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* SDK Configuration
|
|
185
|
+
*/
|
|
186
|
+
interface SDKConfig {
|
|
187
|
+
serviceAccount?: ServiceAccount | string;
|
|
188
|
+
projectId?: string;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Initialize the Firebase Admin SDK with configuration
|
|
192
|
+
* This is optional - the SDK will fall back to environment variables if not called
|
|
193
|
+
*
|
|
194
|
+
* @param config - SDK configuration
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* // Cloudflare Workers
|
|
199
|
+
* export default {
|
|
200
|
+
* async fetch(request, env) {
|
|
201
|
+
* initializeApp({
|
|
202
|
+
* serviceAccount: env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY,
|
|
203
|
+
* projectId: env.FIREBASE_PROJECT_ID
|
|
204
|
+
* });
|
|
205
|
+
* // ... use SDK
|
|
206
|
+
* }
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* // Node.js (optional - will use process.env by default)
|
|
213
|
+
* initializeApp({
|
|
214
|
+
* serviceAccount: JSON.parse(process.env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY),
|
|
215
|
+
* projectId: process.env.FIREBASE_PROJECT_ID
|
|
216
|
+
* });
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
declare function initializeApp(config: SDKConfig): void;
|
|
220
|
+
/**
|
|
221
|
+
* Get the current SDK configuration
|
|
222
|
+
*/
|
|
223
|
+
declare function getConfig(): SDKConfig;
|
|
224
|
+
/**
|
|
225
|
+
* Clear the SDK configuration (useful for testing)
|
|
226
|
+
*/
|
|
227
|
+
declare function clearConfig(): void;
|
|
228
|
+
/**
|
|
229
|
+
* Get service account from config or environment
|
|
230
|
+
* Priority: 1) globalConfig, 2) process.env
|
|
231
|
+
*/
|
|
232
|
+
declare function getServiceAccount(): ServiceAccount;
|
|
233
|
+
/**
|
|
234
|
+
* Get Firebase project ID from config or environment
|
|
235
|
+
* Priority: 1) globalConfig, 2) process.env
|
|
236
|
+
*/
|
|
237
|
+
declare function getProjectId(): string;
|
|
238
|
+
|
|
178
239
|
/**
|
|
179
240
|
* Firebase Admin SDK v8 - Authentication
|
|
180
241
|
* ID token verification supporting both Firebase v9 and v10 token formats
|
|
@@ -451,22 +512,4 @@ declare function getAdminAccessToken(): Promise<string>;
|
|
|
451
512
|
*/
|
|
452
513
|
declare function clearTokenCache(): void;
|
|
453
514
|
|
|
454
|
-
|
|
455
|
-
* Firebase Admin SDK v8 - Service Account Management
|
|
456
|
-
*/
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Get Firebase service account from environment variable
|
|
460
|
-
* @throws {Error} If FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY is not set
|
|
461
|
-
* @returns {ServiceAccount} Parsed service account credentials
|
|
462
|
-
*/
|
|
463
|
-
declare function getServiceAccount(): ServiceAccount;
|
|
464
|
-
/**
|
|
465
|
-
* Get Firebase project ID from environment
|
|
466
|
-
* Checks multiple possible environment variable names
|
|
467
|
-
* @throws {Error} If no project ID is found
|
|
468
|
-
* @returns {string} Firebase project ID
|
|
469
|
-
*/
|
|
470
|
-
declare function getProjectId(): string;
|
|
471
|
-
|
|
472
|
-
export { type BatchWrite, type BatchWriteResult, type DataObject, type DecodedIdToken, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FirestoreDocument, type FirestoreValue, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type TokenResponse, type UpdateOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearTokenCache, deleteDocument, getAdminAccessToken, getAuth, getDocument, getProjectId, getServiceAccount, getUserFromToken, queryDocuments, setDocument, updateDocument, verifyIdToken };
|
|
515
|
+
export { type BatchWrite, type BatchWriteResult, type DataObject, type DecodedIdToken, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FirestoreDocument, type FirestoreValue, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type TokenResponse, type UpdateOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearConfig, clearTokenCache, deleteDocument, getAdminAccessToken, getAuth, getConfig, getDocument, getProjectId, getServiceAccount, getUserFromToken, initializeApp, queryDocuments, setDocument, updateDocument, verifyIdToken };
|
package/dist/index.js
CHANGED
|
@@ -23,14 +23,17 @@ __export(index_exports, {
|
|
|
23
23
|
FieldValue: () => FieldValue,
|
|
24
24
|
addDocument: () => addDocument,
|
|
25
25
|
batchWrite: () => batchWrite,
|
|
26
|
+
clearConfig: () => clearConfig,
|
|
26
27
|
clearTokenCache: () => clearTokenCache,
|
|
27
28
|
deleteDocument: () => deleteDocument,
|
|
28
29
|
getAdminAccessToken: () => getAdminAccessToken,
|
|
29
30
|
getAuth: () => getAuth,
|
|
31
|
+
getConfig: () => getConfig,
|
|
30
32
|
getDocument: () => getDocument,
|
|
31
33
|
getProjectId: () => getProjectId,
|
|
32
34
|
getServiceAccount: () => getServiceAccount,
|
|
33
35
|
getUserFromToken: () => getUserFromToken,
|
|
36
|
+
initializeApp: () => initializeApp,
|
|
34
37
|
queryDocuments: () => queryDocuments,
|
|
35
38
|
setDocument: () => setDocument,
|
|
36
39
|
updateDocument: () => updateDocument,
|
|
@@ -38,12 +41,28 @@ __export(index_exports, {
|
|
|
38
41
|
});
|
|
39
42
|
module.exports = __toCommonJS(index_exports);
|
|
40
43
|
|
|
41
|
-
// src/
|
|
44
|
+
// src/config.ts
|
|
45
|
+
var globalConfig = {};
|
|
46
|
+
function initializeApp(config) {
|
|
47
|
+
globalConfig = { ...config };
|
|
48
|
+
}
|
|
49
|
+
function getConfig() {
|
|
50
|
+
return globalConfig;
|
|
51
|
+
}
|
|
52
|
+
function clearConfig() {
|
|
53
|
+
globalConfig = {};
|
|
54
|
+
}
|
|
42
55
|
function getServiceAccount() {
|
|
43
|
-
|
|
56
|
+
if (globalConfig.serviceAccount) {
|
|
57
|
+
if (typeof globalConfig.serviceAccount === "string") {
|
|
58
|
+
return JSON.parse(globalConfig.serviceAccount);
|
|
59
|
+
}
|
|
60
|
+
return globalConfig.serviceAccount;
|
|
61
|
+
}
|
|
62
|
+
const key = typeof process !== "undefined" && process.env?.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY;
|
|
44
63
|
if (!key) {
|
|
45
64
|
throw new Error(
|
|
46
|
-
|
|
65
|
+
"Firebase service account not configured. Either call initializeApp({ serviceAccount: ... }) or set FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY environment variable."
|
|
47
66
|
);
|
|
48
67
|
}
|
|
49
68
|
try {
|
|
@@ -73,13 +92,18 @@ function getServiceAccount() {
|
|
|
73
92
|
}
|
|
74
93
|
}
|
|
75
94
|
function getProjectId() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
if (globalConfig.projectId) {
|
|
96
|
+
return globalConfig.projectId;
|
|
97
|
+
}
|
|
98
|
+
if (typeof process !== "undefined" && process.env) {
|
|
99
|
+
const projectId = process.env.FIREBASE_PROJECT_ID || process.env.PUBLIC_FIREBASE_PROJECT_ID;
|
|
100
|
+
if (projectId) {
|
|
101
|
+
return projectId;
|
|
102
|
+
}
|
|
81
103
|
}
|
|
82
|
-
|
|
104
|
+
throw new Error(
|
|
105
|
+
"Firebase project ID not configured. Either call initializeApp({ projectId: ... }) or set FIREBASE_PROJECT_ID environment variable."
|
|
106
|
+
);
|
|
83
107
|
}
|
|
84
108
|
|
|
85
109
|
// src/x509.ts
|
|
@@ -173,18 +197,22 @@ async function importPublicKeyFromX509(pem) {
|
|
|
173
197
|
// src/auth.ts
|
|
174
198
|
var publicKeysCache = null;
|
|
175
199
|
var publicKeysCacheExpiry = 0;
|
|
176
|
-
async function fetchPublicKeys() {
|
|
200
|
+
async function fetchPublicKeys(issuer) {
|
|
201
|
+
let endpoint = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
|
|
202
|
+
if (issuer && issuer.includes("session.firebase.google.com")) {
|
|
203
|
+
endpoint = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys";
|
|
204
|
+
}
|
|
177
205
|
if (publicKeysCache && Date.now() < publicKeysCacheExpiry) {
|
|
178
206
|
return publicKeysCache;
|
|
179
207
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
);
|
|
208
|
+
console.log(`[fetchPublicKeys] Fetching from: ${endpoint}`);
|
|
209
|
+
const response = await fetch(endpoint);
|
|
183
210
|
if (!response.ok) {
|
|
184
|
-
throw new Error(
|
|
211
|
+
throw new Error(`Failed to fetch Firebase public keys from ${endpoint}`);
|
|
185
212
|
}
|
|
186
213
|
publicKeysCache = await response.json();
|
|
187
214
|
publicKeysCacheExpiry = Date.now() + 36e5;
|
|
215
|
+
console.log(`[fetchPublicKeys] Fetched ${Object.keys(publicKeysCache || {}).length} keys`);
|
|
188
216
|
return publicKeysCache;
|
|
189
217
|
}
|
|
190
218
|
function base64UrlDecode(str) {
|
|
@@ -257,13 +285,20 @@ async function verifyIdToken(idToken) {
|
|
|
257
285
|
if (payload.sub.length > 128) {
|
|
258
286
|
throw new Error("Subject too long");
|
|
259
287
|
}
|
|
260
|
-
|
|
261
|
-
|
|
288
|
+
let publicKeys = await fetchPublicKeys(payload.iss);
|
|
289
|
+
let publicKeyPem = publicKeys[header.kid];
|
|
262
290
|
if (!publicKeyPem) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
);
|
|
291
|
+
console.log(`[verifyIdToken] Key ${header.kid} not found in cache, refreshing keys...`);
|
|
292
|
+
publicKeysCache = null;
|
|
293
|
+
publicKeysCacheExpiry = 0;
|
|
294
|
+
publicKeys = await fetchPublicKeys(payload.iss);
|
|
295
|
+
publicKeyPem = publicKeys[header.kid];
|
|
296
|
+
if (!publicKeyPem) {
|
|
297
|
+
const availableKids = Object.keys(publicKeys).join(", ");
|
|
298
|
+
throw new Error(
|
|
299
|
+
`Public key not found for kid: ${header.kid}. Available kids: ${availableKids}. This might indicate the token is from a different Firebase project or was signed with a very old key.`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
267
302
|
}
|
|
268
303
|
const publicKey = await importPublicKeyFromX509(publicKeyPem);
|
|
269
304
|
const isValid = await verifySignature(idToken, publicKey);
|
|
@@ -863,14 +898,17 @@ async function batchWrite(operations) {
|
|
|
863
898
|
FieldValue,
|
|
864
899
|
addDocument,
|
|
865
900
|
batchWrite,
|
|
901
|
+
clearConfig,
|
|
866
902
|
clearTokenCache,
|
|
867
903
|
deleteDocument,
|
|
868
904
|
getAdminAccessToken,
|
|
869
905
|
getAuth,
|
|
906
|
+
getConfig,
|
|
870
907
|
getDocument,
|
|
871
908
|
getProjectId,
|
|
872
909
|
getServiceAccount,
|
|
873
910
|
getUserFromToken,
|
|
911
|
+
initializeApp,
|
|
874
912
|
queryDocuments,
|
|
875
913
|
setDocument,
|
|
876
914
|
updateDocument,
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/config.ts
|
|
2
|
+
var globalConfig = {};
|
|
3
|
+
function initializeApp(config) {
|
|
4
|
+
globalConfig = { ...config };
|
|
5
|
+
}
|
|
6
|
+
function getConfig() {
|
|
7
|
+
return globalConfig;
|
|
8
|
+
}
|
|
9
|
+
function clearConfig() {
|
|
10
|
+
globalConfig = {};
|
|
11
|
+
}
|
|
2
12
|
function getServiceAccount() {
|
|
3
|
-
|
|
13
|
+
if (globalConfig.serviceAccount) {
|
|
14
|
+
if (typeof globalConfig.serviceAccount === "string") {
|
|
15
|
+
return JSON.parse(globalConfig.serviceAccount);
|
|
16
|
+
}
|
|
17
|
+
return globalConfig.serviceAccount;
|
|
18
|
+
}
|
|
19
|
+
const key = typeof process !== "undefined" && process.env?.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY;
|
|
4
20
|
if (!key) {
|
|
5
21
|
throw new Error(
|
|
6
|
-
|
|
22
|
+
"Firebase service account not configured. Either call initializeApp({ serviceAccount: ... }) or set FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY environment variable."
|
|
7
23
|
);
|
|
8
24
|
}
|
|
9
25
|
try {
|
|
@@ -33,13 +49,18 @@ function getServiceAccount() {
|
|
|
33
49
|
}
|
|
34
50
|
}
|
|
35
51
|
function getProjectId() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
if (globalConfig.projectId) {
|
|
53
|
+
return globalConfig.projectId;
|
|
54
|
+
}
|
|
55
|
+
if (typeof process !== "undefined" && process.env) {
|
|
56
|
+
const projectId = process.env.FIREBASE_PROJECT_ID || process.env.PUBLIC_FIREBASE_PROJECT_ID;
|
|
57
|
+
if (projectId) {
|
|
58
|
+
return projectId;
|
|
59
|
+
}
|
|
41
60
|
}
|
|
42
|
-
|
|
61
|
+
throw new Error(
|
|
62
|
+
"Firebase project ID not configured. Either call initializeApp({ projectId: ... }) or set FIREBASE_PROJECT_ID environment variable."
|
|
63
|
+
);
|
|
43
64
|
}
|
|
44
65
|
|
|
45
66
|
// src/x509.ts
|
|
@@ -133,18 +154,22 @@ async function importPublicKeyFromX509(pem) {
|
|
|
133
154
|
// src/auth.ts
|
|
134
155
|
var publicKeysCache = null;
|
|
135
156
|
var publicKeysCacheExpiry = 0;
|
|
136
|
-
async function fetchPublicKeys() {
|
|
157
|
+
async function fetchPublicKeys(issuer) {
|
|
158
|
+
let endpoint = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
|
|
159
|
+
if (issuer && issuer.includes("session.firebase.google.com")) {
|
|
160
|
+
endpoint = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys";
|
|
161
|
+
}
|
|
137
162
|
if (publicKeysCache && Date.now() < publicKeysCacheExpiry) {
|
|
138
163
|
return publicKeysCache;
|
|
139
164
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
);
|
|
165
|
+
console.log(`[fetchPublicKeys] Fetching from: ${endpoint}`);
|
|
166
|
+
const response = await fetch(endpoint);
|
|
143
167
|
if (!response.ok) {
|
|
144
|
-
throw new Error(
|
|
168
|
+
throw new Error(`Failed to fetch Firebase public keys from ${endpoint}`);
|
|
145
169
|
}
|
|
146
170
|
publicKeysCache = await response.json();
|
|
147
171
|
publicKeysCacheExpiry = Date.now() + 36e5;
|
|
172
|
+
console.log(`[fetchPublicKeys] Fetched ${Object.keys(publicKeysCache || {}).length} keys`);
|
|
148
173
|
return publicKeysCache;
|
|
149
174
|
}
|
|
150
175
|
function base64UrlDecode(str) {
|
|
@@ -217,13 +242,20 @@ async function verifyIdToken(idToken) {
|
|
|
217
242
|
if (payload.sub.length > 128) {
|
|
218
243
|
throw new Error("Subject too long");
|
|
219
244
|
}
|
|
220
|
-
|
|
221
|
-
|
|
245
|
+
let publicKeys = await fetchPublicKeys(payload.iss);
|
|
246
|
+
let publicKeyPem = publicKeys[header.kid];
|
|
222
247
|
if (!publicKeyPem) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
);
|
|
248
|
+
console.log(`[verifyIdToken] Key ${header.kid} not found in cache, refreshing keys...`);
|
|
249
|
+
publicKeysCache = null;
|
|
250
|
+
publicKeysCacheExpiry = 0;
|
|
251
|
+
publicKeys = await fetchPublicKeys(payload.iss);
|
|
252
|
+
publicKeyPem = publicKeys[header.kid];
|
|
253
|
+
if (!publicKeyPem) {
|
|
254
|
+
const availableKids = Object.keys(publicKeys).join(", ");
|
|
255
|
+
throw new Error(
|
|
256
|
+
`Public key not found for kid: ${header.kid}. Available kids: ${availableKids}. This might indicate the token is from a different Firebase project or was signed with a very old key.`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
227
259
|
}
|
|
228
260
|
const publicKey = await importPublicKeyFromX509(publicKeyPem);
|
|
229
261
|
const isValid = await verifySignature(idToken, publicKey);
|
|
@@ -822,14 +854,17 @@ export {
|
|
|
822
854
|
FieldValue,
|
|
823
855
|
addDocument,
|
|
824
856
|
batchWrite,
|
|
857
|
+
clearConfig,
|
|
825
858
|
clearTokenCache,
|
|
826
859
|
deleteDocument,
|
|
827
860
|
getAdminAccessToken,
|
|
828
861
|
getAuth,
|
|
862
|
+
getConfig,
|
|
829
863
|
getDocument,
|
|
830
864
|
getProjectId,
|
|
831
865
|
getServiceAccount,
|
|
832
866
|
getUserFromToken,
|
|
867
|
+
initializeApp,
|
|
833
868
|
queryDocuments,
|
|
834
869
|
setDocument,
|
|
835
870
|
updateDocument,
|
package/package.json
CHANGED