firebase-admin-edge 1.0.22 → 1.0.23
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 +58 -20
- package/dist/auth/cache-types.d.ts +7 -0
- package/dist/auth/cache-types.d.ts.map +1 -0
- package/dist/auth/cache-types.js +2 -0
- package/dist/auth/cache-types.js.map +1 -0
- package/dist/auth/cookie-types.d.ts +4 -0
- package/dist/auth/cookie-types.d.ts.map +1 -1
- package/dist/auth/firebase-admin-auth.d.ts +75 -10
- package/dist/auth/firebase-admin-auth.d.ts.map +1 -1
- package/dist/auth/firebase-admin-auth.js +111 -28
- package/dist/auth/firebase-admin-auth.js.map +1 -1
- package/dist/auth/firebase-admin-auth.test.js +35 -42
- package/dist/auth/firebase-admin-auth.test.js.map +1 -1
- package/dist/auth/firebase-auth-endpoints.d.ts +8 -2
- package/dist/auth/firebase-auth-endpoints.d.ts.map +1 -1
- package/dist/auth/firebase-auth-endpoints.js +8 -4
- package/dist/auth/firebase-auth-endpoints.js.map +1 -1
- package/dist/auth/firebase-auth-endpoints.test.js +8 -8
- package/dist/auth/firebase-auth-endpoints.test.js.map +1 -1
- package/dist/auth/firebase-auth.d.ts +33 -0
- package/dist/auth/firebase-auth.d.ts.map +1 -1
- package/dist/auth/firebase-auth.js +33 -0
- package/dist/auth/firebase-auth.js.map +1 -1
- package/dist/auth/firebase-jwt.d.ts.map +1 -1
- package/dist/auth/firebase-jwt.js +1 -0
- package/dist/auth/firebase-jwt.js.map +1 -1
- package/dist/auth/google-oauth.d.ts +5 -10
- package/dist/auth/google-oauth.d.ts.map +1 -1
- package/dist/auth/google-oauth.js +12 -1
- package/dist/auth/google-oauth.js.map +1 -1
- package/dist/firebase-edge-server.d.ts +18 -12
- package/dist/firebase-edge-server.d.ts.map +1 -1
- package/dist/firebase-edge-server.js +44 -29
- package/dist/firebase-edge-server.js.map +1 -1
- package/dist/firebase-edge-server.test.js +5 -5
- package/dist/firebase-edge-server.test.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/token-cache.d.ts +9 -0
- package/dist/utils/token-cache.d.ts.map +1 -0
- package/dist/utils/token-cache.js +27 -0
- package/dist/utils/token-cache.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,9 +23,12 @@ npm i firebase-admin-edge
|
|
|
23
23
|
### Basic setup
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
|
-
import { createFirebaseEdgeServer } from 'firebase-admin-edge';
|
|
26
|
+
import { createFirebaseEdgeServer, TokenCache } from 'firebase-admin-edge';
|
|
27
27
|
import { getCookie, setCookie } from 'your-framework-library';
|
|
28
28
|
|
|
29
|
+
// Optional: Create a cache for service account tokens (recommended for performance)
|
|
30
|
+
const cache = new TokenCache();
|
|
31
|
+
|
|
29
32
|
// Create the edge server once during initialization. Keep secrets out of
|
|
30
33
|
// source control — load the `serviceAccount` and client secrets from
|
|
31
34
|
// environment variables or a secret manager.
|
|
@@ -44,6 +47,10 @@ export const firebaseServer = createFirebaseEdgeServer({
|
|
|
44
47
|
google: {
|
|
45
48
|
client_id: 'your-google-oauth-client-id',
|
|
46
49
|
client_secret: 'your-google-oauth-client-secret'
|
|
50
|
+
},
|
|
51
|
+
github: {
|
|
52
|
+
client_id: 'your-github-oauth-client-id',
|
|
53
|
+
client_secret: 'your-github-oauth-client-secret'
|
|
47
54
|
}
|
|
48
55
|
},
|
|
49
56
|
cookies: {
|
|
@@ -51,8 +58,27 @@ export const firebaseServer = createFirebaseEdgeServer({
|
|
|
51
58
|
getSession: (name) => getCookie(name),
|
|
52
59
|
saveSession: (name, value, options) => setCookie(name, value, options)
|
|
53
60
|
},
|
|
61
|
+
// Optional: Token caching for improved performance (tokens cached for 1 hour)
|
|
62
|
+
cache: {
|
|
63
|
+
getCache: (name) => cache.get(name),
|
|
64
|
+
setCache: (name, value, ttl) => cache.set(name, value, ttl)
|
|
65
|
+
},
|
|
66
|
+
// Optional: Custom session cookie name (defaults to '__session')
|
|
67
|
+
cookieName: '__session',
|
|
68
|
+
// Optional: Custom cookie options
|
|
69
|
+
cookieOptions: {
|
|
70
|
+
httpOnly: true,
|
|
71
|
+
secure: true,
|
|
72
|
+
sameSite: 'lax',
|
|
73
|
+
path: '/',
|
|
74
|
+
maxAge: 60 * 60 * 24 * 5 // 5 days
|
|
75
|
+
},
|
|
54
76
|
// OAuth callback URL (registered with your provider)
|
|
55
|
-
redirectUri: 'https://example.com/auth/callback'
|
|
77
|
+
redirectUri: 'https://example.com/auth/callback',
|
|
78
|
+
// Optional: Tenant ID for multi-tenancy
|
|
79
|
+
tenantId: 'your-tenant-id',
|
|
80
|
+
// Optional: Automatically link accounts with same email
|
|
81
|
+
autoLinkProviders: false
|
|
56
82
|
});
|
|
57
83
|
```
|
|
58
84
|
|
|
@@ -99,29 +125,41 @@ redirect(302, '/');
|
|
|
99
125
|
- ✅ **Zero Dependencies** - Uses only fetch API and jose
|
|
100
126
|
- ✅ **TypeScript Support** - Full type safety and IntelliSense
|
|
101
127
|
- ✅ **Session Management** - Secure HTTP-only cookies
|
|
102
|
-
- ✅ **
|
|
128
|
+
- ✅ **OAuth Support** - Google and GitHub OAuth 2.0 flows
|
|
103
129
|
- ✅ **Token Management** - Generate client tokens from server sessions
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- ☐ Magic Link (auto save email
|
|
111
|
-
- ☐
|
|
112
|
-
- ☐
|
|
113
|
-
- ☐
|
|
130
|
+
- ✅ **Token Caching** - Optional caching for service account tokens (1-hour TTL)
|
|
131
|
+
- ✅ **Multi-Tenancy** - Support for Firebase Auth tenant IDs
|
|
132
|
+
- ✅ **Flexible Configuration** - Customizable cookie options and cache implementations
|
|
133
|
+
|
|
134
|
+
## Firebase Auth Todo
|
|
135
|
+
|
|
136
|
+
- ☐ Magic Link Login (auto save email option)
|
|
137
|
+
- ☐ Link and Unlink Providers
|
|
138
|
+
- ☐ Email / Password / Annonymous Login
|
|
139
|
+
- ☐ Reset Password
|
|
140
|
+
- ☐ Change Email
|
|
141
|
+
- ☐ Get User By ID
|
|
142
|
+
- ☐ Get All Users with Order By and Pagination
|
|
143
|
+
- ☐ Create User
|
|
144
|
+
- ☐ Delete
|
|
114
145
|
- ☐ Update User
|
|
115
|
-
- ☐ Delete User
|
|
116
146
|
- ☐ Add / Remove Custom Claims
|
|
117
|
-
- ☐
|
|
118
|
-
- ☐ All Providers
|
|
147
|
+
- ☐ Disable User (Ban User)
|
|
148
|
+
- ☐ Add All Providers
|
|
149
|
+
- ☐ Add App Check
|
|
119
150
|
- ☐ Ban Users
|
|
120
151
|
- ☐ RBAC
|
|
121
152
|
|
|
122
|
-
|
|
153
|
+
## Firestore Todo
|
|
154
|
+
|
|
155
|
+
- ☐ Get Document By ID
|
|
156
|
+
- ☐ Create Document
|
|
157
|
+
- ☐ Update Document (merge option)
|
|
158
|
+
- ☐ Delete Document
|
|
159
|
+
- ☐ Query Documents
|
|
123
160
|
|
|
124
|
-
|
|
125
|
-
- (enableTokenRefreshOnExpiredKidHeader ? cookieSignatureKeys ?)
|
|
161
|
+
## Firebase Storage
|
|
126
162
|
|
|
127
|
-
|
|
163
|
+
- ☐ Create File
|
|
164
|
+
- ☐ Delete File
|
|
165
|
+
- ☐ Get File
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type SetCache = <T>(name: string, value: T, ttlMs?: number) => Promise<void> | void;
|
|
2
|
+
export type GetCache = <T>(name: string) => Promise<T | undefined> | T | undefined;
|
|
3
|
+
export type CacheConfig = {
|
|
4
|
+
getCache: GetCache;
|
|
5
|
+
setCache: SetCache;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=cache-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-types.d.ts","sourceRoot":"","sources":["../../src/auth/cache-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,EACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,CAAC,EACR,KAAK,CAAC,EAAE,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE1B,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,EACrB,IAAI,EAAE,MAAM,KACX,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG;IACtB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-types.js","sourceRoot":"","sources":["../../src/auth/cache-types.ts"],"names":[],"mappings":""}
|
|
@@ -16,4 +16,8 @@ export type CookieOptions = Partial<{
|
|
|
16
16
|
};
|
|
17
17
|
export type GetSession = (name: string) => Promise<string | null | undefined> | string | null | undefined;
|
|
18
18
|
export type SetSession = (name: string, value: string, options: CookieOptions) => Promise<void> | void;
|
|
19
|
+
export type CookieConfig = {
|
|
20
|
+
getSession: GetSession;
|
|
21
|
+
saveSession: SetSession;
|
|
22
|
+
};
|
|
19
23
|
//# sourceMappingURL=cookie-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-types.d.ts","sourceRoot":"","sources":["../../src/auth/cookie-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC7B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IAChC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACjD,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,MAAM,MAAM,UAAU,GAAG,CACrB,IAAI,EAAE,MAAM,KACX,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG,CACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,KACrB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC"}
|
|
1
|
+
{"version":3,"file":"cookie-types.d.ts","sourceRoot":"","sources":["../../src/auth/cookie-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC7B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IAChC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACjD,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,MAAM,MAAM,UAAU,GAAG,CACrB,IAAI,EAAE,MAAM,KACX,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG,CACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,KACrB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE1B,MAAM,MAAM,YAAY,GAAG;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,UAAU,CAAC;CAC3B,CAAC"}
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import type { ServiceAccount } from './firebase-types.js';
|
|
2
2
|
import { FirebaseEdgeError } from './errors.js';
|
|
3
|
+
import type { CacheConfig } from './cache-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Firebase Admin Authentication handler for edge environments.
|
|
6
|
+
* Provides server-side authentication operations using service account credentials.
|
|
7
|
+
*/
|
|
3
8
|
export declare class FirebaseAdminAuth {
|
|
4
9
|
private serviceAccountKey;
|
|
5
10
|
private tenantId?;
|
|
6
11
|
private fetch?;
|
|
7
|
-
|
|
12
|
+
private cache?;
|
|
13
|
+
private cacheName?;
|
|
14
|
+
private _cacheName;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new Firebase Admin Auth instance.
|
|
17
|
+
*
|
|
18
|
+
* @param serviceAccountKey Firebase service account credentials
|
|
19
|
+
* @param tenantId Optional tenant ID for multi-tenancy
|
|
20
|
+
* @param fetch Optional custom fetch implementation
|
|
21
|
+
* @param cache Optional cache implementation for token caching
|
|
22
|
+
* @param cacheName Optional cache key name (defaults to '__cache')
|
|
23
|
+
*/
|
|
24
|
+
constructor(serviceAccountKey: ServiceAccount, tenantId?: string | undefined, fetch?: typeof globalThis.fetch | undefined, cache?: CacheConfig | undefined, cacheName?: string | undefined);
|
|
25
|
+
/**
|
|
26
|
+
* Retrieves a cached service account token or fetches a new one.
|
|
27
|
+
* Tokens are cached for 1 hour.
|
|
28
|
+
*
|
|
29
|
+
* @returns Promise with token data and error
|
|
30
|
+
*/
|
|
31
|
+
private getCachedToken;
|
|
32
|
+
/**
|
|
33
|
+
* Retrieves user account information by UID.
|
|
34
|
+
*
|
|
35
|
+
* @param uid User ID to look up
|
|
36
|
+
* @returns Promise with object containing user data or null, and error if any
|
|
37
|
+
*/
|
|
8
38
|
getUser(uid: string): Promise<{
|
|
9
39
|
data: null;
|
|
10
40
|
error: FirebaseEdgeError;
|
|
@@ -12,29 +42,64 @@ export declare class FirebaseAdminAuth {
|
|
|
12
42
|
data: import("./firebase-types.js").UserRecord | null | undefined;
|
|
13
43
|
error: null;
|
|
14
44
|
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Retrieves user account information by email address.
|
|
47
|
+
*
|
|
48
|
+
* @param email Email address to look up
|
|
49
|
+
* @returns Promise with object containing user data or null, and error if any
|
|
50
|
+
*/
|
|
51
|
+
getUserByEmail(email: string): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Verifies a Firebase ID token and returns the decoded payload.
|
|
54
|
+
* Optionally checks if the token has been revoked.
|
|
55
|
+
*
|
|
56
|
+
* @param idToken Firebase ID token to verify
|
|
57
|
+
* @param checkRevoked Whether to check if token has been revoked (defaults to false)
|
|
58
|
+
* @returns Promise with object containing decoded token payload or null, and error if any
|
|
59
|
+
*/
|
|
15
60
|
verifyIdToken(idToken: string, checkRevoked?: boolean): Promise<{
|
|
61
|
+
data: null;
|
|
62
|
+
error: FirebaseEdgeError;
|
|
63
|
+
} | {
|
|
16
64
|
data: import("./firebase-types.js").FirebaseIdTokenPayload;
|
|
17
65
|
error: null;
|
|
18
|
-
} | {
|
|
19
|
-
data: null;
|
|
20
|
-
error: Error;
|
|
21
66
|
}>;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Creates a session cookie from a Firebase ID token.
|
|
69
|
+
*
|
|
70
|
+
* @param idToken Firebase ID token to convert to session cookie
|
|
71
|
+
* @param expiresIn_ms Session cookie expiration time in milliseconds
|
|
72
|
+
* @returns Promise with object containing session cookie string or null, and error if any
|
|
73
|
+
*/
|
|
74
|
+
createSessionCookie(idToken: string, expiresIn_ms: number): Promise<{
|
|
25
75
|
data: null;
|
|
26
76
|
error: FirebaseEdgeError;
|
|
27
77
|
} | {
|
|
28
78
|
data: string | null;
|
|
29
79
|
error: null;
|
|
30
80
|
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Verifies a Firebase session cookie and returns the decoded payload.
|
|
83
|
+
* Optionally checks if the token has been revoked.
|
|
84
|
+
*
|
|
85
|
+
* @param sessionCookie Session cookie to verify
|
|
86
|
+
* @param checkRevoked Whether to check if token has been revoked (defaults to false)
|
|
87
|
+
* @returns Promise with object containing decoded session payload or null, and error if any
|
|
88
|
+
*/
|
|
31
89
|
verifySessionCookie(sessionCookie: string, checkRevoked?: boolean): Promise<{
|
|
90
|
+
data: null;
|
|
91
|
+
error: FirebaseEdgeError;
|
|
92
|
+
} | {
|
|
32
93
|
data: import("./firebase-types.js").FirebaseIdTokenPayload;
|
|
33
94
|
error: null;
|
|
34
|
-
} | {
|
|
35
|
-
data: null;
|
|
36
|
-
error: Error;
|
|
37
95
|
}>;
|
|
96
|
+
/**
|
|
97
|
+
* Creates a custom Firebase authentication token for a given user.
|
|
98
|
+
*
|
|
99
|
+
* @param uid User ID to create token for
|
|
100
|
+
* @param developerClaims Optional custom claims to include in the token
|
|
101
|
+
* @returns Promise with object containing custom token string or null, and error if any
|
|
102
|
+
*/
|
|
38
103
|
createCustomToken(uid: string, developerClaims?: object): Promise<{
|
|
39
104
|
data: null;
|
|
40
105
|
error: FirebaseEdgeError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-admin-auth.d.ts","sourceRoot":"","sources":["../../src/auth/firebase-admin-auth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"firebase-admin-auth.d.ts","sourceRoot":"","sources":["../../src/auth/firebase-admin-auth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAuB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACH,iBAAiB,EAGpB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;GAGG;AACH,qBAAa,iBAAiB;IAatB,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,QAAQ,CAAC;IACjB,OAAO,CAAC,KAAK,CAAC;IACd,OAAO,CAAC,KAAK,CAAC;IACd,OAAO,CAAC,SAAS,CAAC;IAhBtB,OAAO,CAAC,UAAU,CAAa;IAE/B;;;;;;;;OAQG;gBAES,iBAAiB,EAAE,cAAc,EACjC,QAAQ,CAAC,EAAE,MAAM,YAAA,EACjB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,YAAA,EAC/B,KAAK,CAAC,EAAE,WAAW,YAAA,EACnB,SAAS,CAAC,EAAE,MAAM,YAAA;IAK9B;;;;;OAKG;YACW,cAAc;IAoC5B;;;;;OAKG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM;;;;;;;IA+BzB;;;;;OAKG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM;IAElC;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe;;;;;;;IA6GlE;;;;;;OAMG;IACG,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;IAuC/D;;;;;;;OAOG;IACG,mBAAmB,CACrB,aAAa,EAAE,MAAM,EACrB,YAAY,GAAE,OAAe;;;;;;;IAgFjC;;;;;;OAMG;IACG,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,GAAE,MAAW;;;;;;;CAmCpE"}
|
|
@@ -1,32 +1,80 @@
|
|
|
1
|
-
import { createSessionCookie,
|
|
1
|
+
import { createSessionCookie, getAccountInfo } from './firebase-auth-endpoints.js';
|
|
2
2
|
import { signJWTCustomToken, verifyJWT, verifySessionJWT } from './firebase-jwt.js';
|
|
3
3
|
import { getToken } from './google-oauth.js';
|
|
4
4
|
import { FirebaseEdgeError, FirebaseAdminAuthErrorInfo, ensureError } from './errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Firebase Admin Authentication handler for edge environments.
|
|
7
|
+
* Provides server-side authentication operations using service account credentials.
|
|
8
|
+
*/
|
|
5
9
|
export class FirebaseAdminAuth {
|
|
6
10
|
serviceAccountKey;
|
|
7
11
|
tenantId;
|
|
8
12
|
fetch;
|
|
9
|
-
|
|
13
|
+
cache;
|
|
14
|
+
cacheName;
|
|
15
|
+
_cacheName = '__cache';
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new Firebase Admin Auth instance.
|
|
18
|
+
*
|
|
19
|
+
* @param serviceAccountKey Firebase service account credentials
|
|
20
|
+
* @param tenantId Optional tenant ID for multi-tenancy
|
|
21
|
+
* @param fetch Optional custom fetch implementation
|
|
22
|
+
* @param cache Optional cache implementation for token caching
|
|
23
|
+
* @param cacheName Optional cache key name (defaults to '__cache')
|
|
24
|
+
*/
|
|
25
|
+
constructor(serviceAccountKey, tenantId, fetch, cache, cacheName) {
|
|
10
26
|
this.serviceAccountKey = serviceAccountKey;
|
|
11
27
|
this.tenantId = tenantId;
|
|
12
28
|
this.fetch = fetch;
|
|
29
|
+
this.cache = cache;
|
|
30
|
+
this.cacheName = cacheName;
|
|
31
|
+
this._cacheName = this.cacheName || this._cacheName;
|
|
13
32
|
}
|
|
14
|
-
|
|
15
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Retrieves a cached service account token or fetches a new one.
|
|
35
|
+
* Tokens are cached for 1 hour.
|
|
36
|
+
*
|
|
37
|
+
* @returns Promise with token data and error
|
|
38
|
+
*/
|
|
39
|
+
async getCachedToken() {
|
|
40
|
+
const cachedToken = await this.cache?.getCache(this._cacheName);
|
|
41
|
+
if (cachedToken) {
|
|
42
|
+
return {
|
|
43
|
+
data: cachedToken,
|
|
44
|
+
error: null
|
|
45
|
+
};
|
|
46
|
+
}
|
|
16
47
|
const { data: token, error: getTokenError } = await getToken(this.serviceAccountKey, this.fetch);
|
|
48
|
+
if (token && this.cache) {
|
|
49
|
+
// Google tokens are valid for 1 hour
|
|
50
|
+
this.cache?.setCache('token', token, 3600);
|
|
51
|
+
}
|
|
17
52
|
if (getTokenError) {
|
|
18
53
|
return {
|
|
19
54
|
data: null,
|
|
20
|
-
error:
|
|
55
|
+
error: getTokenError
|
|
21
56
|
};
|
|
22
57
|
}
|
|
23
|
-
|
|
58
|
+
return {
|
|
59
|
+
data: token,
|
|
60
|
+
error: null
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Retrieves user account information by UID.
|
|
65
|
+
*
|
|
66
|
+
* @param uid User ID to look up
|
|
67
|
+
* @returns Promise with object containing user data or null, and error if any
|
|
68
|
+
*/
|
|
69
|
+
async getUser(uid) {
|
|
70
|
+
const { data: token, error: tokenError } = await this.getCachedToken();
|
|
71
|
+
if (tokenError) {
|
|
24
72
|
return {
|
|
25
73
|
data: null,
|
|
26
|
-
error:
|
|
74
|
+
error: tokenError
|
|
27
75
|
};
|
|
28
76
|
}
|
|
29
|
-
const { data, error } = await
|
|
77
|
+
const { data, error } = await getAccountInfo({ uid }, token.access_token, this.serviceAccountKey.project_id, this.tenantId, this.fetch);
|
|
30
78
|
if (error) {
|
|
31
79
|
return {
|
|
32
80
|
data: null,
|
|
@@ -38,6 +86,21 @@ export class FirebaseAdminAuth {
|
|
|
38
86
|
error: null
|
|
39
87
|
};
|
|
40
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Retrieves user account information by email address.
|
|
91
|
+
*
|
|
92
|
+
* @param email Email address to look up
|
|
93
|
+
* @returns Promise with object containing user data or null, and error if any
|
|
94
|
+
*/
|
|
95
|
+
async getUserByEmail(email) { }
|
|
96
|
+
/**
|
|
97
|
+
* Verifies a Firebase ID token and returns the decoded payload.
|
|
98
|
+
* Optionally checks if the token has been revoked.
|
|
99
|
+
*
|
|
100
|
+
* @param idToken Firebase ID token to verify
|
|
101
|
+
* @param checkRevoked Whether to check if token has been revoked (defaults to false)
|
|
102
|
+
* @returns Promise with object containing decoded token payload or null, and error if any
|
|
103
|
+
*/
|
|
41
104
|
async verifyIdToken(idToken, checkRevoked = false) {
|
|
42
105
|
const { data: decodedIdToken, error: verifyError } = await verifyJWT(idToken, this.serviceAccountKey.project_id, this.fetch);
|
|
43
106
|
if (verifyError) {
|
|
@@ -58,8 +121,11 @@ export class FirebaseAdminAuth {
|
|
|
58
121
|
if (tokenTenantId !== this.tenantId) {
|
|
59
122
|
return {
|
|
60
123
|
data: null,
|
|
61
|
-
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.
|
|
62
|
-
|
|
124
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_TENANT_ID_INVALID, {
|
|
125
|
+
context: {
|
|
126
|
+
tokenTenantId,
|
|
127
|
+
expectedTenantId: this.tenantId
|
|
128
|
+
}
|
|
63
129
|
})
|
|
64
130
|
};
|
|
65
131
|
}
|
|
@@ -74,13 +140,13 @@ export class FirebaseAdminAuth {
|
|
|
74
140
|
if (userError) {
|
|
75
141
|
return {
|
|
76
142
|
data: null,
|
|
77
|
-
error: new
|
|
143
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_USER_LOOKUP_FAILED, { cause: ensureError(userError) })
|
|
78
144
|
};
|
|
79
145
|
}
|
|
80
146
|
if (!user) {
|
|
81
147
|
return {
|
|
82
148
|
data: null,
|
|
83
|
-
error: new
|
|
149
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_USER_RECORD_NOT_FOUND)
|
|
84
150
|
};
|
|
85
151
|
}
|
|
86
152
|
if (user.disabled) {
|
|
@@ -107,21 +173,22 @@ export class FirebaseAdminAuth {
|
|
|
107
173
|
error: null
|
|
108
174
|
};
|
|
109
175
|
}
|
|
110
|
-
|
|
111
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Creates a session cookie from a Firebase ID token.
|
|
178
|
+
*
|
|
179
|
+
* @param idToken Firebase ID token to convert to session cookie
|
|
180
|
+
* @param expiresIn_ms Session cookie expiration time in milliseconds
|
|
181
|
+
* @returns Promise with object containing session cookie string or null, and error if any
|
|
182
|
+
*/
|
|
183
|
+
async createSessionCookie(idToken, expiresIn_ms) {
|
|
184
|
+
const { data: token, error: getTokenError } = await this.getCachedToken();
|
|
112
185
|
if (getTokenError) {
|
|
113
186
|
return {
|
|
114
187
|
data: null,
|
|
115
188
|
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED, { cause: getTokenError })
|
|
116
189
|
};
|
|
117
190
|
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
data: null,
|
|
121
|
-
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_NO_TOKEN_RETURNED)
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
const { data, error } = await createSessionCookie(idToken, token.access_token, this.serviceAccountKey.project_id, expiresIn, this.tenantId, this.fetch);
|
|
191
|
+
const { data, error } = await createSessionCookie(idToken, token.access_token, this.serviceAccountKey.project_id, expiresIn_ms, this.tenantId, this.fetch);
|
|
125
192
|
if (error) {
|
|
126
193
|
return {
|
|
127
194
|
data: null,
|
|
@@ -133,6 +200,14 @@ export class FirebaseAdminAuth {
|
|
|
133
200
|
error: null
|
|
134
201
|
};
|
|
135
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Verifies a Firebase session cookie and returns the decoded payload.
|
|
205
|
+
* Optionally checks if the token has been revoked.
|
|
206
|
+
*
|
|
207
|
+
* @param sessionCookie Session cookie to verify
|
|
208
|
+
* @param checkRevoked Whether to check if token has been revoked (defaults to false)
|
|
209
|
+
* @returns Promise with object containing decoded session payload or null, and error if any
|
|
210
|
+
*/
|
|
136
211
|
async verifySessionCookie(sessionCookie, checkRevoked = false) {
|
|
137
212
|
const { data, error } = await verifySessionJWT(sessionCookie, this.serviceAccountKey.project_id, this.fetch);
|
|
138
213
|
if (error) {
|
|
@@ -144,9 +219,7 @@ export class FirebaseAdminAuth {
|
|
|
144
219
|
if (!data) {
|
|
145
220
|
return {
|
|
146
221
|
data: null,
|
|
147
|
-
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_VERIFY_FAILED
|
|
148
|
-
cause: new Error('No data returned from session cookie verification')
|
|
149
|
-
})
|
|
222
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_VERIFY_FAILED)
|
|
150
223
|
};
|
|
151
224
|
}
|
|
152
225
|
// Validate tenant ID if specified
|
|
@@ -155,8 +228,11 @@ export class FirebaseAdminAuth {
|
|
|
155
228
|
if (tokenTenantId !== this.tenantId) {
|
|
156
229
|
return {
|
|
157
230
|
data: null,
|
|
158
|
-
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.
|
|
159
|
-
|
|
231
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_TENANT_ID_INVALID, {
|
|
232
|
+
context: {
|
|
233
|
+
tokenTenantId,
|
|
234
|
+
expectedTenantId: this.tenantId
|
|
235
|
+
}
|
|
160
236
|
})
|
|
161
237
|
};
|
|
162
238
|
}
|
|
@@ -171,13 +247,13 @@ export class FirebaseAdminAuth {
|
|
|
171
247
|
if (userError) {
|
|
172
248
|
return {
|
|
173
249
|
data: null,
|
|
174
|
-
error: new
|
|
250
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_USER_LOOKUP_FAILED, { cause: ensureError(userError) })
|
|
175
251
|
};
|
|
176
252
|
}
|
|
177
253
|
if (!user) {
|
|
178
254
|
return {
|
|
179
255
|
data: null,
|
|
180
|
-
error: new
|
|
256
|
+
error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_USER_RECORD_NOT_FOUND)
|
|
181
257
|
};
|
|
182
258
|
}
|
|
183
259
|
return {
|
|
@@ -185,6 +261,13 @@ export class FirebaseAdminAuth {
|
|
|
185
261
|
error: null
|
|
186
262
|
};
|
|
187
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Creates a custom Firebase authentication token for a given user.
|
|
266
|
+
*
|
|
267
|
+
* @param uid User ID to create token for
|
|
268
|
+
* @param developerClaims Optional custom claims to include in the token
|
|
269
|
+
* @returns Promise with object containing custom token string or null, and error if any
|
|
270
|
+
*/
|
|
188
271
|
async createCustomToken(uid, developerClaims = {}) {
|
|
189
272
|
const claims = this.tenantId
|
|
190
273
|
? { ...developerClaims, tenant_id: this.tenantId }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-admin-auth.js","sourceRoot":"","sources":["../../src/auth/firebase-admin-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,
|
|
1
|
+
{"version":3,"file":"firebase-admin-auth.js","sourceRoot":"","sources":["../../src/auth/firebase-admin-auth.ts"],"names":[],"mappings":"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"}
|