firebase-admin-edge 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +26 -0
  2. package/dist/auth/auth-endpoint-errors.d.ts +15 -0
  3. package/dist/auth/auth-endpoint-errors.d.ts.map +1 -0
  4. package/dist/auth/auth-endpoint-errors.js +120 -0
  5. package/dist/auth/auth-endpoint-errors.js.map +1 -0
  6. package/dist/auth/auth-error-codes.d.ts +777 -0
  7. package/dist/auth/auth-error-codes.d.ts.map +1 -0
  8. package/dist/auth/auth-error-codes.js +823 -0
  9. package/dist/auth/auth-error-codes.js.map +1 -0
  10. package/dist/auth/errors.d.ts +20 -0
  11. package/dist/auth/errors.d.ts.map +1 -0
  12. package/dist/auth/errors.js +29 -0
  13. package/dist/auth/errors.js.map +1 -0
  14. package/dist/auth/firebase-admin-auth.d.ts +12 -21
  15. package/dist/auth/firebase-admin-auth.d.ts.map +1 -1
  16. package/dist/auth/firebase-admin-auth.js +54 -16
  17. package/dist/auth/firebase-admin-auth.js.map +1 -1
  18. package/dist/auth/firebase-admin-auth.test.js +36 -24
  19. package/dist/auth/firebase-admin-auth.test.js.map +1 -1
  20. package/dist/auth/firebase-auth-endpoints.d.ts +13 -77
  21. package/dist/auth/firebase-auth-endpoints.d.ts.map +1 -1
  22. package/dist/auth/firebase-auth-endpoints.js +53 -37
  23. package/dist/auth/firebase-auth-endpoints.js.map +1 -1
  24. package/dist/auth/firebase-auth-endpoints.test.js +178 -13
  25. package/dist/auth/firebase-auth-endpoints.test.js.map +1 -1
  26. package/dist/auth/firebase-auth.d.ts +5 -9
  27. package/dist/auth/firebase-auth.d.ts.map +1 -1
  28. package/dist/auth/firebase-auth.js +61 -21
  29. package/dist/auth/firebase-auth.js.map +1 -1
  30. package/dist/auth/firebase-auth.test.js +29 -12
  31. package/dist/auth/firebase-auth.test.js.map +1 -1
  32. package/dist/auth/firebase-jwt.d.ts +5 -29
  33. package/dist/auth/firebase-jwt.d.ts.map +1 -1
  34. package/dist/auth/firebase-jwt.js +74 -33
  35. package/dist/auth/firebase-jwt.js.map +1 -1
  36. package/dist/auth/firebase-jwt.test.js +31 -11
  37. package/dist/auth/firebase-jwt.test.js.map +1 -1
  38. package/dist/auth/github-oauth.d.ts +5 -2
  39. package/dist/auth/github-oauth.d.ts.map +1 -1
  40. package/dist/auth/github-oauth.js +126 -13
  41. package/dist/auth/github-oauth.js.map +1 -1
  42. package/dist/auth/github-oauth.test.d.ts +2 -0
  43. package/dist/auth/github-oauth.test.d.ts.map +1 -0
  44. package/dist/auth/github-oauth.test.js +202 -0
  45. package/dist/auth/github-oauth.test.js.map +1 -0
  46. package/dist/auth/google-oauth.d.ts +3 -3
  47. package/dist/auth/google-oauth.d.ts.map +1 -1
  48. package/dist/auth/google-oauth.js +89 -26
  49. package/dist/auth/google-oauth.js.map +1 -1
  50. package/dist/auth/google-oauth.test.js +105 -35
  51. package/dist/auth/google-oauth.test.js.map +1 -1
  52. package/dist/auth/oauth.d.ts +3 -0
  53. package/dist/auth/oauth.d.ts.map +1 -0
  54. package/dist/auth/oauth.js +28 -0
  55. package/dist/auth/oauth.js.map +1 -0
  56. package/dist/auth/oauth.test.d.ts +2 -0
  57. package/dist/auth/oauth.test.d.ts.map +1 -0
  58. package/dist/auth/oauth.test.js +233 -0
  59. package/dist/auth/oauth.test.js.map +1 -0
  60. package/dist/firebase-edge-errors.d.ts +95 -0
  61. package/dist/firebase-edge-errors.d.ts.map +1 -0
  62. package/dist/firebase-edge-errors.js +102 -0
  63. package/dist/firebase-edge-errors.js.map +1 -0
  64. package/dist/firebase-edge-errors.test.d.ts +2 -0
  65. package/dist/firebase-edge-errors.test.d.ts.map +1 -0
  66. package/dist/firebase-edge-errors.test.js +72 -0
  67. package/dist/firebase-edge-errors.test.js.map +1 -0
  68. package/dist/firebase-edge-server.d.ts +5 -4
  69. package/dist/firebase-edge-server.d.ts.map +1 -1
  70. package/dist/firebase-edge-server.js +22 -17
  71. package/dist/firebase-edge-server.js.map +1 -1
  72. package/dist/firebase-edge-server.test.js +55 -7
  73. package/dist/firebase-edge-server.test.js.map +1 -1
  74. package/package.json +1 -1
@@ -2,100 +2,36 @@ import type { FirebaseCreateAuthUriResponse, FirebaseIdpSignInResponse, Firebase
2
2
  import type { JsonWebKey } from 'crypto';
3
3
  export declare function refreshFirebaseIdToken(refreshToken: string, key: string, fetchFn?: typeof globalThis.fetch): Promise<{
4
4
  data: FirebaseRefreshTokenResponse | null;
5
- error: {
6
- code: number;
7
- message: string;
8
- errors?: {
9
- message: string;
10
- domain: string;
11
- reason: string;
12
- }[];
13
- } | null;
5
+ error: import("./errors.js").FirebaseEdgeError | null;
14
6
  }>;
15
- export declare function createAuthUri(redirect_uri: string, key: string, fetchFn?: typeof globalThis.fetch): Promise<{
7
+ export declare function createAuthUri(redirect_uri: string, key: string, tenantId?: string, fetchFn?: typeof globalThis.fetch): Promise<{
16
8
  data: FirebaseCreateAuthUriResponse | null;
17
- error: {
18
- code: number;
19
- message: string;
20
- errors?: {
21
- message: string;
22
- domain: string;
23
- reason: string;
24
- }[];
25
- } | null;
9
+ error: import("./errors.js").FirebaseEdgeError | null;
26
10
  }>;
27
- export declare function signInWithIdp(providerIdToken: string, requestUri: string, providerId: string | undefined, key: string, fetchFn?: typeof globalThis.fetch): Promise<{
11
+ export declare function signInWithIdp(providerIdToken: string, requestUri: string, providerId: string | undefined, key: string, tenantId?: string, fetchFn?: typeof globalThis.fetch): Promise<{
28
12
  data: FirebaseIdpSignInResponse | null;
29
- error: {
30
- code: number;
31
- message: string;
32
- errors?: {
33
- message: string;
34
- domain: string;
35
- reason: string;
36
- }[];
37
- } | null;
13
+ error: import("./errors.js").FirebaseEdgeError | null;
38
14
  }>;
39
- export declare function signInWithCustomToken(jwtToken: string, key: string, fetchFn?: typeof globalThis.fetch): Promise<{
15
+ export declare function signInWithCustomToken(jwtToken: string, key: string, tenantId?: string, fetchFn?: typeof globalThis.fetch): Promise<{
40
16
  data: FirebaseIdpSignInResponse | null;
41
- error: {
42
- code: number;
43
- message: string;
44
- errors?: {
45
- message: string;
46
- domain: string;
47
- reason: string;
48
- }[];
49
- } | null;
17
+ error: import("./errors.js").FirebaseEdgeError | null;
50
18
  }>;
51
- export declare function getAccountInfoByUid(uid: string, token: string, project_id: string, fetchFn?: typeof globalThis.fetch): Promise<{
19
+ export declare function getAccountInfoByUid(uid: string, token: string, project_id: string, tenantId?: string, fetchFn?: typeof globalThis.fetch): Promise<{
52
20
  data: UserRecord | null | undefined;
53
- error: {
54
- code: number;
55
- message: string;
56
- errors?: {
57
- message: string;
58
- domain: string;
59
- reason: string;
60
- }[];
61
- } | null;
21
+ error: import("./errors.js").FirebaseEdgeError | null;
62
22
  }>;
63
- export declare function createSessionCookie(idToken: string, token: string, project_id: string, expiresIn?: number, fetchFn?: typeof globalThis.fetch): Promise<{
23
+ export declare function createSessionCookie(idToken: string, token: string, project_id: string, expiresIn?: number, tenantId?: string, fetchFn?: typeof globalThis.fetch): Promise<{
64
24
  data: string | null;
65
- error: {
66
- code: number;
67
- message: string;
68
- errors?: {
69
- message: string;
70
- domain: string;
71
- reason: string;
72
- }[];
73
- } | null;
25
+ error: import("./errors.js").FirebaseEdgeError | null;
74
26
  }>;
75
27
  export declare function getJWKs(fetchFn?: typeof globalThis.fetch): Promise<{
76
28
  data: (JsonWebKey & {
77
29
  kid: string;
78
30
  })[] | null;
79
- error: {
80
- code: number;
81
- message: string;
82
- errors?: {
83
- message: string;
84
- domain: string;
85
- reason: string;
86
- }[];
87
- } | null;
31
+ error: import("./errors.js").FirebaseEdgeError | null;
88
32
  }>;
89
33
  export declare function getPublicKeys(fetchFn?: typeof globalThis.fetch): Promise<{
90
34
  data: Record<string, string> | null;
91
- error: {
92
- code: number;
93
- message: string;
94
- errors?: {
95
- message: string;
96
- domain: string;
97
- reason: string;
98
- }[];
99
- } | null;
35
+ error: import("./errors.js").FirebaseEdgeError | null;
100
36
  }>;
101
37
  //# sourceMappingURL=firebase-auth-endpoints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"firebase-auth-endpoints.d.ts","sourceRoot":"","sources":["../../src/auth/firebase-auth-endpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,6BAA6B,EAC7B,yBAAyB,EACzB,4BAA4B,EAE5B,UAAU,EACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAgBzC,wBAAsB,sBAAsB,CACxC,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAuBpC;AAED,wBAAsB,aAAa,CAC/B,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAsBpC;AAED,wBAAsB,aAAa,CAC/B,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,UAAU,oBAAe,EACzB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAgCpC;AAED,wBAAsB,qBAAqB,CACvC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAsBpC;AAED,wBAAsB,mBAAmB,CACrC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAmBpC;AAED,wBAAsB,mBAAmB,CACrC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAiC,EAC5C,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAwBpC;AAED,wBAAsB,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;aAK1B,MAAM;;;;;;;;;;;GAW1C;AAED,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;;;;;;;;;GAgBpE"}
1
+ {"version":3,"file":"firebase-auth-endpoints.d.ts","sourceRoot":"","sources":["../../src/auth/firebase-auth-endpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,6BAA6B,EAC7B,yBAAyB,EACzB,4BAA4B,EAE5B,UAAU,EACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAuBzC,wBAAsB,sBAAsB,CACxC,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GAuBpC;AAED,wBAAsB,aAAa,CAC/B,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GAyBpC;AAED,wBAAsB,aAAa,CAC/B,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,UAAU,oBAAe,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GAmCpC;AAED,wBAAsB,qBAAqB,CACvC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GAyBpC;AAED,wBAAsB,mBAAmB,CACrC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GAsBpC;AAED,wBAAsB,mBAAmB,CACrC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAiC,EAC5C,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GA4BpC;AAED,wBAAsB,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;aAK1B,MAAM;;;GAW1C;AAED,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK;;;GAgBpE"}
@@ -1,9 +1,15 @@
1
1
  import { restFetch } from '../rest-fetch.js';
2
+ import { mapFirebaseError } from './auth-endpoint-errors.js';
2
3
  // Functions
3
- function createAdminIdentityURL(project_id, name, accounts = true) {
4
+ function createAdminIdentityURL(project_id, name, accounts = true, tenantId) {
5
+ if (tenantId) {
6
+ // Use Identity Platform API for tenant-specific operations
7
+ return `https://identitytoolkit.googleapis.com/v1/projects/${project_id}/tenants/${tenantId}${accounts ? '/accounts' : ''}:${name}`;
8
+ }
4
9
  return `https://identitytoolkit.googleapis.com/v1/projects/${project_id}${accounts ? '/accounts' : ''}:${name}`;
5
10
  }
6
11
  function createIdentityURL(name) {
12
+ // Standard Firebase Auth REST API - tenant ID goes in request body, not URL
7
13
  return `https://identitytoolkit.googleapis.com/v1/accounts:${name}`;
8
14
  }
9
15
  export async function refreshFirebaseIdToken(refreshToken, key, fetchFn) {
@@ -21,94 +27,104 @@ export async function refreshFirebaseIdToken(refreshToken, key, fetchFn) {
21
27
  });
22
28
  return {
23
29
  data,
24
- error: error ? error.error : null
30
+ error: error ? mapFirebaseError(error.error) : null
25
31
  };
26
32
  }
27
- export async function createAuthUri(redirect_uri, key, fetchFn) {
33
+ export async function createAuthUri(redirect_uri, key, tenantId, fetchFn) {
28
34
  const url = createIdentityURL('createAuthUri');
35
+ const body = {
36
+ continueUri: redirect_uri,
37
+ providerId: 'google.com',
38
+ ...(tenantId && { tenantId })
39
+ };
29
40
  const { data, error } = await restFetch(url, {
30
41
  global: { fetch: fetchFn },
31
- body: {
32
- continueUri: redirect_uri,
33
- providerId: 'google.com'
34
- },
42
+ body,
35
43
  params: {
36
44
  key
37
45
  }
38
46
  });
39
47
  return {
40
48
  data,
41
- error: error ? error.error : null
49
+ error: error ? mapFirebaseError(error.error) : null
42
50
  };
43
51
  }
44
- export async function signInWithIdp(providerIdToken, requestUri, providerId = 'google.com', key, fetchFn) {
52
+ export async function signInWithIdp(providerIdToken, requestUri, providerId = 'google.com', key, tenantId, fetchFn) {
45
53
  const url = createIdentityURL('signInWithIdp');
46
54
  const tokenField = providerId === 'github.com' ? 'access_token' : 'id_token';
47
55
  const postBody = new URLSearchParams({
48
56
  [tokenField]: providerIdToken,
49
57
  providerId
50
58
  }).toString();
59
+ const body = {
60
+ postBody,
61
+ requestUri,
62
+ returnSecureToken: true,
63
+ returnIdpCredential: true,
64
+ ...(tenantId && { tenantId })
65
+ };
51
66
  const { data, error } = await restFetch(url, {
52
67
  global: { fetch: fetchFn },
53
- body: {
54
- postBody,
55
- requestUri,
56
- returnSecureToken: true,
57
- returnIdpCredential: true
58
- },
68
+ body,
59
69
  params: {
60
70
  key
61
71
  }
62
72
  });
63
73
  return {
64
74
  data,
65
- error: error ? error.error : null
75
+ error: error ? mapFirebaseError(error.error) : null
66
76
  };
67
77
  }
68
- export async function signInWithCustomToken(jwtToken, key, fetchFn) {
78
+ export async function signInWithCustomToken(jwtToken, key, tenantId, fetchFn) {
69
79
  const url = createIdentityURL('signInWithCustomToken');
80
+ const body = {
81
+ token: jwtToken,
82
+ returnSecureToken: true,
83
+ ...(tenantId && { tenantId })
84
+ };
70
85
  const { data, error } = await restFetch(url, {
71
86
  global: { fetch: fetchFn },
72
- body: {
73
- token: jwtToken,
74
- returnSecureToken: true
75
- },
87
+ body,
76
88
  params: {
77
89
  key
78
90
  }
79
91
  });
80
92
  return {
81
93
  data,
82
- error: error ? error.error : null
94
+ error: error ? mapFirebaseError(error.error) : null
83
95
  };
84
96
  }
85
- export async function getAccountInfoByUid(uid, token, project_id, fetchFn) {
86
- const url = createAdminIdentityURL(project_id, 'lookup');
97
+ export async function getAccountInfoByUid(uid, token, project_id, tenantId, fetchFn) {
98
+ const url = createAdminIdentityURL(project_id, 'lookup', true, tenantId);
99
+ const body = {
100
+ localId: uid,
101
+ ...(tenantId && { tenantId })
102
+ };
87
103
  const { data, error } = await restFetch(url, {
88
104
  global: { fetch: fetchFn },
89
- body: {
90
- localId: uid
91
- },
105
+ body,
92
106
  bearerToken: token
93
107
  });
94
108
  return {
95
109
  data: data?.users.length ? data.users[0] : null,
96
- error: error ? error.error : null
110
+ error: error ? mapFirebaseError(error.error) : null
97
111
  };
98
112
  }
99
- export async function createSessionCookie(idToken, token, project_id, expiresIn = 60 * 60 * 24 * 14 * 1000, fetchFn) {
100
- const url = createAdminIdentityURL(project_id, 'createSessionCookie', false);
113
+ export async function createSessionCookie(idToken, token, project_id, expiresIn = 60 * 60 * 24 * 14 * 1000, tenantId, fetchFn) {
114
+ const url = createAdminIdentityURL(project_id, 'createSessionCookie', false, tenantId);
115
+ const body = {
116
+ idToken,
117
+ validDuration: Math.floor(expiresIn / 1000),
118
+ ...(tenantId && { tenantId })
119
+ };
101
120
  const { data, error } = await restFetch(url, {
102
121
  global: { fetch: fetchFn },
103
- body: {
104
- idToken,
105
- validDuration: Math.floor(expiresIn / 1000)
106
- },
122
+ body,
107
123
  bearerToken: token
108
124
  });
109
125
  return {
110
126
  data: data?.sessionCookie || null,
111
- error: error ? error.error : null
127
+ error: error ? mapFirebaseError(error.error) : null
112
128
  };
113
129
  }
114
130
  export async function getJWKs(fetchFn) {
@@ -119,7 +135,7 @@ export async function getJWKs(fetchFn) {
119
135
  });
120
136
  return {
121
137
  data: data?.keys || null,
122
- error: error ? error.error : null
138
+ error: error ? mapFirebaseError(error.error) : null
123
139
  };
124
140
  }
125
141
  export async function getPublicKeys(fetchFn) {
@@ -130,7 +146,7 @@ export async function getPublicKeys(fetchFn) {
130
146
  });
131
147
  return {
132
148
  data,
133
- error: error ? error.error : null
149
+ error: error ? mapFirebaseError(error.error) : null
134
150
  };
135
151
  }
136
152
  //# sourceMappingURL=firebase-auth-endpoints.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"firebase-auth-endpoints.js","sourceRoot":"","sources":["../../src/auth/firebase-auth-endpoints.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"firebase-auth-endpoints.js","sourceRoot":"","sources":["../../src/auth/firebase-auth-endpoints.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import { refreshFirebaseIdToken, createAuthUri, signInWithIdp, signInWithCustomToken, getAccountInfoByUid, createSessionCookie, getJWKs, getPublicKeys } from './firebase-auth-endpoints.js';
3
3
  import * as restFetch from '../rest-fetch.js';
4
+ import { FirebaseEdgeError, FirebaseEndpointErrorInfo } from './errors.js';
4
5
  vi.mock('../rest-fetch.js');
5
6
  describe('firebase-auth-endpoints', () => {
6
7
  const mockFetch = vi.fn();
@@ -36,14 +37,18 @@ describe('firebase-auth-endpoints', () => {
36
37
  }));
37
38
  });
38
39
  it('should handle error response', async () => {
39
- const mockError = { message: 'Invalid refresh token' };
40
+ const mockError = {
41
+ code: 400,
42
+ message: 'INVALID_GRANT: Invalid refresh token'
43
+ };
40
44
  vi.mocked(restFetch.restFetch).mockResolvedValue({
41
45
  data: null,
42
46
  error: { error: mockError }
43
47
  });
44
48
  const result = await refreshFirebaseIdToken('invalid-token', API_KEY);
45
49
  expect(result.data).toBeNull();
46
- expect(result.error).toEqual(mockError);
50
+ expect(result.error).toBeInstanceOf(FirebaseEdgeError);
51
+ expect(result.error.code).toBe(FirebaseEndpointErrorInfo.ENDPOINT_INVALID_REFRESH_TOKEN.code);
47
52
  });
48
53
  });
49
54
  describe('createAuthUri', () => {
@@ -55,7 +60,7 @@ describe('firebase-auth-endpoints', () => {
55
60
  data: mockResponse,
56
61
  error: null
57
62
  });
58
- const result = await createAuthUri('https://redirect.com', API_KEY, mockFetch);
63
+ const result = await createAuthUri('https://redirect.com', API_KEY, undefined, mockFetch);
59
64
  expect(result.data).toEqual(mockResponse);
60
65
  expect(restFetchSpy).toHaveBeenCalled();
61
66
  expect(result.error).toBeNull();
@@ -68,6 +73,28 @@ describe('firebase-auth-endpoints', () => {
68
73
  global: { fetch: mockFetch }
69
74
  }));
70
75
  });
76
+ it('should create auth URI with tenant ID', async () => {
77
+ const mockResponse = { authUri: 'https://auth.example.com' };
78
+ const tenantId = 'tenant-123';
79
+ const restFetchSpy = vi
80
+ .mocked(restFetch.restFetch)
81
+ .mockResolvedValue({
82
+ data: mockResponse,
83
+ error: null
84
+ });
85
+ const result = await createAuthUri('https://redirect.com', API_KEY, tenantId, mockFetch);
86
+ expect(result.data).toEqual(mockResponse);
87
+ expect(result.error).toBeNull();
88
+ expect(restFetchSpy).toHaveBeenCalledWith('https://identitytoolkit.googleapis.com/v1/accounts:createAuthUri', expect.objectContaining({
89
+ body: {
90
+ continueUri: 'https://redirect.com',
91
+ providerId: 'google.com',
92
+ tenantId: tenantId
93
+ },
94
+ params: { key: API_KEY },
95
+ global: { fetch: mockFetch }
96
+ }));
97
+ });
71
98
  });
72
99
  describe('signInWithIdp', () => {
73
100
  it('should sign in with IDP successfully', async () => {
@@ -79,7 +106,7 @@ describe('firebase-auth-endpoints', () => {
79
106
  data: mockResponse,
80
107
  error: null
81
108
  });
82
- const result = await signInWithIdp('provider-token', 'https://request.com', 'google.com', API_KEY, mockFetch);
109
+ const result = await signInWithIdp('provider-token', 'https://request.com', 'google.com', API_KEY, undefined, mockFetch);
83
110
  expect(result.data).toEqual(mockResponse);
84
111
  expect(result.error).toBeNull();
85
112
  expect(restFetch.restFetch).toHaveBeenCalledWith('https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp', expect.objectContaining({
@@ -91,6 +118,50 @@ describe('firebase-auth-endpoints', () => {
91
118
  }
92
119
  }));
93
120
  });
121
+ it('should sign in with IDP and tenant ID', async () => {
122
+ const mockResponse = {
123
+ idToken: 'firebase-token',
124
+ refreshToken: 'refresh'
125
+ };
126
+ const tenantId = 'tenant-456';
127
+ const restFetchSpy = vi
128
+ .mocked(restFetch.restFetch)
129
+ .mockResolvedValue({
130
+ data: mockResponse,
131
+ error: null
132
+ });
133
+ const result = await signInWithIdp('provider-token', 'https://request.com', 'google.com', API_KEY, tenantId, mockFetch);
134
+ expect(result.data).toEqual(mockResponse);
135
+ expect(result.error).toBeNull();
136
+ expect(restFetchSpy).toHaveBeenCalledWith('https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp', expect.objectContaining({
137
+ body: {
138
+ postBody: 'id_token=provider-token&providerId=google.com',
139
+ requestUri: 'https://request.com',
140
+ returnSecureToken: true,
141
+ returnIdpCredential: true,
142
+ tenantId: tenantId
143
+ }
144
+ }));
145
+ });
146
+ it('should use access_token for GitHub provider', async () => {
147
+ const mockResponse = {
148
+ idToken: 'firebase-token',
149
+ refreshToken: 'refresh'
150
+ };
151
+ const restFetchSpy = vi
152
+ .mocked(restFetch.restFetch)
153
+ .mockResolvedValue({
154
+ data: mockResponse,
155
+ error: null
156
+ });
157
+ const result = await signInWithIdp('github-token', 'https://request.com', 'github.com', API_KEY, undefined, mockFetch);
158
+ expect(result.data).toEqual(mockResponse);
159
+ expect(restFetchSpy).toHaveBeenCalledWith('https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp', expect.objectContaining({
160
+ body: expect.objectContaining({
161
+ postBody: 'access_token=github-token&providerId=github.com'
162
+ })
163
+ }));
164
+ });
94
165
  });
95
166
  describe('signInWithCustomToken', () => {
96
167
  it('should sign in with custom token successfully', async () => {
@@ -99,10 +170,30 @@ describe('firebase-auth-endpoints', () => {
99
170
  data: mockResponse,
100
171
  error: null
101
172
  });
102
- const result = await signInWithCustomToken('jwt-token', API_KEY, mockFetch);
173
+ const result = await signInWithCustomToken('jwt-token', API_KEY, undefined, mockFetch);
103
174
  expect(result.data).toEqual(mockResponse);
104
175
  expect(result.error).toBeNull();
105
176
  });
177
+ it('should sign in with custom token and tenant ID', async () => {
178
+ const mockResponse = { idToken: 'firebase-token' };
179
+ const tenantId = 'tenant-789';
180
+ const restFetchSpy = vi
181
+ .mocked(restFetch.restFetch)
182
+ .mockResolvedValue({
183
+ data: mockResponse,
184
+ error: null
185
+ });
186
+ const result = await signInWithCustomToken('jwt-token', API_KEY, tenantId, mockFetch);
187
+ expect(result.data).toEqual(mockResponse);
188
+ expect(result.error).toBeNull();
189
+ expect(restFetchSpy).toHaveBeenCalledWith('https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken', expect.objectContaining({
190
+ body: {
191
+ token: 'jwt-token',
192
+ returnSecureToken: true,
193
+ tenantId: tenantId
194
+ }
195
+ }));
196
+ });
106
197
  });
107
198
  describe('getAccountInfoByUid', () => {
108
199
  it('should get account info successfully', async () => {
@@ -111,9 +202,29 @@ describe('firebase-auth-endpoints', () => {
111
202
  data: { users: [mockUser] },
112
203
  error: null
113
204
  });
114
- const result = await getAccountInfoByUid('user-123', ACCESS_TOKEN, PROJECT_ID, mockFetch);
205
+ const result = await getAccountInfoByUid('user-123', ACCESS_TOKEN, PROJECT_ID, undefined, mockFetch);
206
+ expect(result.data).toEqual(mockUser);
207
+ expect(result.error).toBeNull();
208
+ });
209
+ it('should get account info with tenant ID', async () => {
210
+ const mockUser = { localId: 'user-123', email: 'test@example.com' };
211
+ const tenantId = 'tenant-abc';
212
+ const restFetchSpy = vi
213
+ .mocked(restFetch.restFetch)
214
+ .mockResolvedValue({
215
+ data: { users: [mockUser] },
216
+ error: null
217
+ });
218
+ const result = await getAccountInfoByUid('user-123', ACCESS_TOKEN, PROJECT_ID, tenantId, mockFetch);
115
219
  expect(result.data).toEqual(mockUser);
116
220
  expect(result.error).toBeNull();
221
+ expect(restFetchSpy).toHaveBeenCalledWith(`https://identitytoolkit.googleapis.com/v1/projects/${PROJECT_ID}/tenants/${tenantId}/accounts:lookup`, expect.objectContaining({
222
+ body: {
223
+ localId: 'user-123',
224
+ tenantId: tenantId
225
+ },
226
+ bearerToken: ACCESS_TOKEN
227
+ }));
117
228
  });
118
229
  it('should return null when no users found', async () => {
119
230
  vi.mocked(restFetch.restFetch).mockResolvedValue({
@@ -133,7 +244,7 @@ describe('firebase-auth-endpoints', () => {
133
244
  data: mockResponse,
134
245
  error: null
135
246
  });
136
- const result = await createSessionCookie('id-token', ACCESS_TOKEN, PROJECT_ID, undefined, mockFetch);
247
+ const result = await createSessionCookie('id-token', ACCESS_TOKEN, PROJECT_ID, undefined, undefined, mockFetch);
137
248
  expect(result.data).toBe('cookie-value');
138
249
  expect(restFetchSpy).toHaveBeenCalledWith(`https://identitytoolkit.googleapis.com/v1/projects/${PROJECT_ID}:createSessionCookie`, expect.objectContaining({
139
250
  body: expect.objectContaining({
@@ -142,6 +253,27 @@ describe('firebase-auth-endpoints', () => {
142
253
  })
143
254
  }));
144
255
  });
256
+ it('should create session cookie with tenant ID', async () => {
257
+ const mockResponse = { sessionCookie: 'cookie-value' };
258
+ const tenantId = 'tenant-def';
259
+ const restFetchSpy = vi
260
+ .mocked(restFetch.restFetch)
261
+ .mockResolvedValue({
262
+ data: mockResponse,
263
+ error: null
264
+ });
265
+ const result = await createSessionCookie('id-token', ACCESS_TOKEN, PROJECT_ID, 3600000, // 1 hour in ms
266
+ tenantId, mockFetch);
267
+ expect(result.data).toBe('cookie-value');
268
+ expect(restFetchSpy).toHaveBeenCalledWith(`https://identitytoolkit.googleapis.com/v1/projects/${PROJECT_ID}/tenants/${tenantId}:createSessionCookie`, expect.objectContaining({
269
+ body: {
270
+ idToken: 'id-token',
271
+ validDuration: 3600, // converted to seconds
272
+ tenantId: tenantId
273
+ },
274
+ bearerToken: ACCESS_TOKEN
275
+ }));
276
+ });
145
277
  it('should create session cookie with custom expiry (using seconds)', async () => {
146
278
  const mockResponse = { sessionCookie: 'cookie-value' };
147
279
  vi.mocked(restFetch.restFetch).mockResolvedValue({
@@ -149,7 +281,7 @@ describe('firebase-auth-endpoints', () => {
149
281
  error: null
150
282
  });
151
283
  const result = await createSessionCookie('id-token', ACCESS_TOKEN, PROJECT_ID, 3600, // 1 hour in seconds
152
- mockFetch);
284
+ undefined, mockFetch);
153
285
  expect(result.data).toBe('cookie-value');
154
286
  });
155
287
  });
@@ -185,17 +317,21 @@ describe('firebase-auth-endpoints', () => {
185
317
  expect(result.error).toBeNull();
186
318
  });
187
319
  it('should handle error response', async () => {
188
- const mockError = { message: 'Failed to fetch keys' };
320
+ const mockError = {
321
+ code: 403,
322
+ message: 'PERMISSION_DENIED: Failed to fetch keys'
323
+ };
189
324
  vi.mocked(restFetch.restFetch).mockResolvedValue({
190
325
  data: null,
191
326
  error: { error: mockError }
192
327
  });
193
328
  const result = await getPublicKeys();
194
329
  expect(result.data).toBeNull();
195
- expect(result.error).toEqual(mockError);
330
+ expect(result.error).toBeInstanceOf(FirebaseEdgeError);
331
+ expect(result.error.code).toBe(FirebaseEndpointErrorInfo.ENDPOINT_PERMISSION_DENIED.code);
196
332
  });
197
333
  });
198
- describe('createAdminIdentityURL (indirectly via createSessionCookie)', () => {
334
+ describe('createAdminIdentityURL (indirectly via functions)', () => {
199
335
  it('should call createSessionCookie URL without /accounts segment', async () => {
200
336
  const mockResponse = { sessionCookie: 'cookie-value' };
201
337
  const restFetchSpy = vi
@@ -207,7 +343,7 @@ describe('firebase-auth-endpoints', () => {
207
343
  const idToken = 'id-token';
208
344
  const token = 'access-token';
209
345
  const projectId = 'test-project';
210
- const result = await createSessionCookie(idToken, token, projectId, 3600_000, vi.fn());
346
+ const result = await createSessionCookie(idToken, token, projectId, 3600_000, undefined, vi.fn());
211
347
  expect(result.data).toBe('cookie-value');
212
348
  expect(restFetchSpy).toHaveBeenCalledTimes(1);
213
349
  const [calledUrl, options] = restFetchSpy.mock
@@ -216,6 +352,20 @@ describe('firebase-auth-endpoints', () => {
216
352
  expect(options.bearerToken).toBe(token);
217
353
  expect(options.body.idToken).toBe(idToken);
218
354
  });
355
+ it('should call createSessionCookie tenant URL when tenant ID provided', async () => {
356
+ const mockResponse = { sessionCookie: 'cookie-value' };
357
+ const tenantId = 'tenant-test';
358
+ const restFetchSpy = vi
359
+ .mocked(restFetch.restFetch)
360
+ .mockResolvedValue({
361
+ data: mockResponse,
362
+ error: null
363
+ });
364
+ const result = await createSessionCookie('id-token', 'access-token', 'test-project', 3600_000, tenantId, vi.fn());
365
+ expect(result.data).toBe('cookie-value');
366
+ const [calledUrl] = restFetchSpy.mock.calls[0];
367
+ expect(calledUrl).toBe(`https://identitytoolkit.googleapis.com/v1/projects/test-project/tenants/${tenantId}:createSessionCookie`);
368
+ });
219
369
  it('should call accounts lookup URL with /accounts segment via getAccountInfoByUid', async () => {
220
370
  const mockUser = { localId: 'user-123', email: 'test@example.com' };
221
371
  const restFetchSpy = vi
@@ -227,7 +377,7 @@ describe('firebase-auth-endpoints', () => {
227
377
  const uid = 'user-123';
228
378
  const token = 'access-token';
229
379
  const projectId = 'test-project';
230
- const result = await getAccountInfoByUid(uid, token, projectId, vi.fn());
380
+ const result = await getAccountInfoByUid(uid, token, projectId, undefined, vi.fn());
231
381
  expect(result.data).toEqual(mockUser);
232
382
  expect(restFetchSpy).toHaveBeenCalledTimes(1);
233
383
  const [calledUrl, options] = restFetchSpy.mock
@@ -236,6 +386,20 @@ describe('firebase-auth-endpoints', () => {
236
386
  expect(options.bearerToken).toBe(token);
237
387
  expect(options.body.localId).toBe(uid);
238
388
  });
389
+ it('should call accounts lookup tenant URL when tenant ID provided', async () => {
390
+ const mockUser = { localId: 'user-123', email: 'test@example.com' };
391
+ const tenantId = 'tenant-lookup';
392
+ const restFetchSpy = vi
393
+ .mocked(restFetch.restFetch)
394
+ .mockResolvedValue({
395
+ data: { users: [mockUser] },
396
+ error: null
397
+ });
398
+ const result = await getAccountInfoByUid('user-123', 'access-token', 'test-project', tenantId, vi.fn());
399
+ expect(result.data).toEqual(mockUser);
400
+ const [calledUrl] = restFetchSpy.mock.calls[0];
401
+ expect(calledUrl).toBe(`https://identitytoolkit.googleapis.com/v1/projects/test-project/tenants/${tenantId}/accounts:lookup`);
402
+ });
239
403
  });
240
404
  describe('createSessionCookie with ms input', () => {
241
405
  it('should convert ms to seconds when creating session cookie', async () => {
@@ -247,6 +411,7 @@ describe('firebase-auth-endpoints', () => {
247
411
  error: null
248
412
  });
249
413
  const result = await createSessionCookie('id-token', ACCESS_TOKEN, PROJECT_ID, 1209600000, // 14 days in ms
414
+ undefined, // tenantId
250
415
  mockFetch);
251
416
  expect(result.data).toBe('cookie-value');
252
417
  expect(restFetchSpy).toHaveBeenCalledWith(expect.stringContaining('createSessionCookie'), expect.objectContaining({