firebase-admin-edge 1.0.5 → 1.0.10
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/LICENSE +20 -20
- package/README.md +90 -1
- package/dist/firebase-edge-server.d.ts +62 -1
- package/dist/firebase-edge-server.d.ts.map +1 -1
- package/dist/firebase-edge-server.js +263 -2
- package/dist/firebase-edge-server.js.map +1 -1
- package/package.json +5 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Jonathan Gamble
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jonathan Gamble
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# Firebase Admin Edge
|
|
2
2
|
|
|
3
3
|
Use Firebase Admin on the edge:
|
|
4
4
|
|
|
@@ -10,3 +10,92 @@ Use Firebase Admin on the edge:
|
|
|
10
10
|
- Node.js
|
|
11
11
|
|
|
12
12
|
Uses Rest API under the hood and has no side effects.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i -D firebase-admin-edge
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### Basic Setup
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { createFirebaseEdgeServer } from 'firebase-admin-edge';
|
|
26
|
+
import { getCookie, setCookie } from 'your-framework-library';
|
|
27
|
+
|
|
28
|
+
export const firebaseServer = createFirebaseEdgeServer({
|
|
29
|
+
serviceAccount: {
|
|
30
|
+
type: 'service_account',
|
|
31
|
+
project_id: 'your-project-id',
|
|
32
|
+
private_key_id: 'your-private-key-id',
|
|
33
|
+
...
|
|
34
|
+
},
|
|
35
|
+
firebaseConfig: {
|
|
36
|
+
apiKey: 'your-web-api-key',
|
|
37
|
+
authDomain: 'your-project.firebaseapp.com',
|
|
38
|
+
...
|
|
39
|
+
},
|
|
40
|
+
providers: {
|
|
41
|
+
google: {
|
|
42
|
+
client_id: 'your-google-oauth-client-id',
|
|
43
|
+
client_secret: 'your-google-oauth-client-secret',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
cookies: {
|
|
47
|
+
getSession: (name) => {
|
|
48
|
+
return getCookie(name);
|
|
49
|
+
},
|
|
50
|
+
saveSession: (name, value, options) => {
|
|
51
|
+
return setCookie(name, value, options);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Get User
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const { data: user } = await firebaseServer.getUser();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Login With Google Code
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// Currently only supports Google Provider, more coming soon!
|
|
67
|
+
|
|
68
|
+
const { error } = await firebaseServer.signInWithGoogleWithCode(
|
|
69
|
+
code,
|
|
70
|
+
redirect_uri,
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Create Google Login URL
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// Normally you need a browser to do this!
|
|
78
|
+
|
|
79
|
+
const loginUrl = await firebaseServer.getGoogleLoginURL(redirect_uri, path);
|
|
80
|
+
|
|
81
|
+
// Your framework redirect method
|
|
82
|
+
redirect(302, loginUrl);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Logout
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
firebaseServer.signOut();
|
|
89
|
+
|
|
90
|
+
// Your framework redirect method
|
|
91
|
+
redirect(302, '/');
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Features
|
|
95
|
+
|
|
96
|
+
- ✅ **Edge Runtime Compatible** - Works in Vercel Edge, Cloudflare Workers, Deno, and Bun
|
|
97
|
+
- ✅ **Zero Dependencies** - Uses only fetch API and jose
|
|
98
|
+
- ✅ **TypeScript Support** - Full type safety and IntelliSense
|
|
99
|
+
- ✅ **Session Management** - Secure HTTP-only cookies
|
|
100
|
+
- ✅ **Google OAuth** - Complete OAuth 2.0 flow
|
|
101
|
+
- ✅ **Token Management** - Generate client tokens from server sessions
|
|
@@ -2,7 +2,12 @@ import type { GetSession, SetSession } from './auth/cookie-types.js';
|
|
|
2
2
|
import { FirebaseAdminAuth } from './auth/firebase-admin-auth.js';
|
|
3
3
|
import { FirebaseAuth } from './auth/firebase-auth.js';
|
|
4
4
|
import type { FirebaseConfig, ServiceAccount } from './auth/firebase-types.js';
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Official Firebase OAuth providers supported by Firebase Auth
|
|
7
|
+
* @constant
|
|
8
|
+
* @type {readonly string[]}
|
|
9
|
+
*/
|
|
10
|
+
export declare const OFFICIAL_FIREBASE_OAUTH_PROVIDERS: readonly string[];
|
|
6
11
|
type ProviderList = (typeof OFFICIAL_FIREBASE_OAUTH_PROVIDERS)[number];
|
|
7
12
|
type ProviderConfig = Partial<Record<ProviderList, {
|
|
8
13
|
client_id: string;
|
|
@@ -13,6 +18,62 @@ type CookieConfig = {
|
|
|
13
18
|
saveSession: SetSession;
|
|
14
19
|
sessionName?: string;
|
|
15
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Creates a Firebase Edge Server instance with authentication and session management capabilities.
|
|
23
|
+
*
|
|
24
|
+
* This function sets up a complete Firebase authentication system that works in edge environments
|
|
25
|
+
* like Cloudflare Workers, Vercel Edge Functions, and other serverless platforms.
|
|
26
|
+
*
|
|
27
|
+
* @param config - Configuration object for the Firebase Edge Server
|
|
28
|
+
* @param config.serviceAccount - Firebase service account credentials for admin operations
|
|
29
|
+
* @param config.firebaseConfig - Firebase project configuration (apiKey, authDomain, etc.)
|
|
30
|
+
* @param config.providers - OAuth provider configurations (Google, Facebook, etc.)
|
|
31
|
+
* @param config.cookies - Cookie management configuration for session handling
|
|
32
|
+
* @param config.fetch - Optional custom fetch implementation (defaults to globalThis.fetch)
|
|
33
|
+
*
|
|
34
|
+
* @returns Object containing authentication methods and utilities
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const server = createFirebaseEdgeServer({
|
|
39
|
+
* serviceAccount: {
|
|
40
|
+
* type: "service_account",
|
|
41
|
+
* project_id: "your-project-id",
|
|
42
|
+
* private_key_id: "...",
|
|
43
|
+
* private_key: "...",
|
|
44
|
+
* client_email: "...",
|
|
45
|
+
* client_id: "...",
|
|
46
|
+
* auth_uri: "...",
|
|
47
|
+
* token_uri: "...",
|
|
48
|
+
* auth_provider_x509_cert_url: "...",
|
|
49
|
+
* client_x509_cert_url: "..."
|
|
50
|
+
* },
|
|
51
|
+
* firebaseConfig: {
|
|
52
|
+
* apiKey: "your-api-key",
|
|
53
|
+
* authDomain: "your-project.firebaseapp.com",
|
|
54
|
+
* projectId: "your-project-id"
|
|
55
|
+
* },
|
|
56
|
+
* providers: {
|
|
57
|
+
* google: {
|
|
58
|
+
* client_id: "your-google-client-id",
|
|
59
|
+
* client_secret: "your-google-client-secret"
|
|
60
|
+
* }
|
|
61
|
+
* },
|
|
62
|
+
* cookies: {
|
|
63
|
+
* getSession: (name) => getCookie(name),
|
|
64
|
+
* saveSession: (name, value, options) => setCookie(name, value, options)
|
|
65
|
+
* }
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // Using guard clauses for clean error handling
|
|
69
|
+
* const { data: user, error } = await server.getUser();
|
|
70
|
+
* if (error) return handleError(error);
|
|
71
|
+
* if (!user) return redirectToLogin();
|
|
72
|
+
*
|
|
73
|
+
* // User is authenticated, proceed with protected logic
|
|
74
|
+
* console.log('Authenticated user:', user.email);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
16
77
|
export declare function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, providers, cookies, fetch, }: {
|
|
17
78
|
serviceAccount: ServiceAccount;
|
|
18
79
|
firebaseConfig: FirebaseConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-edge-server.d.ts","sourceRoot":"","sources":["../src/firebase-edge-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAER,UAAU,EACV,UAAU,EACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAgB/E,eAAO,MAAM,iCAAiC,
|
|
1
|
+
{"version":3,"file":"firebase-edge-server.d.ts","sourceRoot":"","sources":["../src/firebase-edge-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAER,UAAU,EACV,UAAU,EACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAgB/E;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,EAAE,SAAS,MAAM,EASrD,CAAC;AAEX,KAAK,YAAY,GAAG,CAAC,OAAO,iCAAiC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvE,KAAK,cAAc,GAAG,OAAO,CACzB,MAAM,CACF,YAAY,EACZ;IACI,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACzB,CACJ,CACJ,CAAC;AAEF,KAAK,YAAY,GAAG;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,wBAAgB,wBAAwB,CAAC,EACrC,cAAc,EACd,cAAc,EACd,SAAS,EACT,OAAO,EACP,KAAK,GACR,EAAE;IACC,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,cAAc,CAAC;IAC1B,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACnC;;;;6BA+EwC,OAAO;;;;;;;;;;;;;;;;;;;;sCA8EG,MAAM,QAAQ,MAAM;qCA+DzD,MAAM,gBACE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgM3B"}
|
|
@@ -10,6 +10,11 @@ const COOKIE_OPTIONS = {
|
|
|
10
10
|
path: '/',
|
|
11
11
|
maxAge: 60 * 60 * 24 * 5 * 1000,
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Official Firebase OAuth providers supported by Firebase Auth
|
|
15
|
+
* @constant
|
|
16
|
+
* @type {readonly string[]}
|
|
17
|
+
*/
|
|
13
18
|
export const OFFICIAL_FIREBASE_OAUTH_PROVIDERS = [
|
|
14
19
|
'google',
|
|
15
20
|
'facebook',
|
|
@@ -20,6 +25,62 @@ export const OFFICIAL_FIREBASE_OAUTH_PROVIDERS = [
|
|
|
20
25
|
'yahoo',
|
|
21
26
|
'playgames',
|
|
22
27
|
];
|
|
28
|
+
/**
|
|
29
|
+
* Creates a Firebase Edge Server instance with authentication and session management capabilities.
|
|
30
|
+
*
|
|
31
|
+
* This function sets up a complete Firebase authentication system that works in edge environments
|
|
32
|
+
* like Cloudflare Workers, Vercel Edge Functions, and other serverless platforms.
|
|
33
|
+
*
|
|
34
|
+
* @param config - Configuration object for the Firebase Edge Server
|
|
35
|
+
* @param config.serviceAccount - Firebase service account credentials for admin operations
|
|
36
|
+
* @param config.firebaseConfig - Firebase project configuration (apiKey, authDomain, etc.)
|
|
37
|
+
* @param config.providers - OAuth provider configurations (Google, Facebook, etc.)
|
|
38
|
+
* @param config.cookies - Cookie management configuration for session handling
|
|
39
|
+
* @param config.fetch - Optional custom fetch implementation (defaults to globalThis.fetch)
|
|
40
|
+
*
|
|
41
|
+
* @returns Object containing authentication methods and utilities
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const server = createFirebaseEdgeServer({
|
|
46
|
+
* serviceAccount: {
|
|
47
|
+
* type: "service_account",
|
|
48
|
+
* project_id: "your-project-id",
|
|
49
|
+
* private_key_id: "...",
|
|
50
|
+
* private_key: "...",
|
|
51
|
+
* client_email: "...",
|
|
52
|
+
* client_id: "...",
|
|
53
|
+
* auth_uri: "...",
|
|
54
|
+
* token_uri: "...",
|
|
55
|
+
* auth_provider_x509_cert_url: "...",
|
|
56
|
+
* client_x509_cert_url: "..."
|
|
57
|
+
* },
|
|
58
|
+
* firebaseConfig: {
|
|
59
|
+
* apiKey: "your-api-key",
|
|
60
|
+
* authDomain: "your-project.firebaseapp.com",
|
|
61
|
+
* projectId: "your-project-id"
|
|
62
|
+
* },
|
|
63
|
+
* providers: {
|
|
64
|
+
* google: {
|
|
65
|
+
* client_id: "your-google-client-id",
|
|
66
|
+
* client_secret: "your-google-client-secret"
|
|
67
|
+
* }
|
|
68
|
+
* },
|
|
69
|
+
* cookies: {
|
|
70
|
+
* getSession: (name) => getCookie(name),
|
|
71
|
+
* saveSession: (name, value, options) => setCookie(name, value, options)
|
|
72
|
+
* }
|
|
73
|
+
* });
|
|
74
|
+
*
|
|
75
|
+
* // Using guard clauses for clean error handling
|
|
76
|
+
* const { data: user, error } = await server.getUser();
|
|
77
|
+
* if (error) return handleError(error);
|
|
78
|
+
* if (!user) return redirectToLogin();
|
|
79
|
+
*
|
|
80
|
+
* // User is authenticated, proceed with protected logic
|
|
81
|
+
* console.log('Authenticated user:', user.email);
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
23
84
|
export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, providers, cookies, fetch, }) {
|
|
24
85
|
const sessionName = cookies.sessionName || DEFAULT_SESSION_NAME;
|
|
25
86
|
const getSession = cookies.getSession;
|
|
@@ -27,16 +88,73 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
27
88
|
const fetchImpl = fetch ?? globalThis.fetch;
|
|
28
89
|
const auth = new FirebaseAuth(firebaseConfig, fetchImpl);
|
|
29
90
|
const adminAuth = new FirebaseAdminAuth(serviceAccount, fetchImpl);
|
|
91
|
+
/**
|
|
92
|
+
* Deletes the current user session by clearing the session cookie.
|
|
93
|
+
*
|
|
94
|
+
* This is an internal helper function used by signOut and error handlers to ensure
|
|
95
|
+
* clean session management when authentication fails or users sign out.
|
|
96
|
+
*
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
30
99
|
function deleteSession() {
|
|
31
100
|
saveSession(sessionName, '', {
|
|
32
101
|
...COOKIE_OPTIONS,
|
|
33
102
|
maxAge: 0,
|
|
34
103
|
});
|
|
35
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Signs out the current user by deleting their session cookie.
|
|
107
|
+
*
|
|
108
|
+
* This method only removes the local session and does not revoke the user's Firebase tokens.
|
|
109
|
+
* For complete logout, consider also calling Firebase client-side signOut if needed.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* // Simple sign out
|
|
114
|
+
* server.signOut();
|
|
115
|
+
*
|
|
116
|
+
* // With redirect after sign out
|
|
117
|
+
* server.signOut();
|
|
118
|
+
* return redirect('/login');
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
36
121
|
function signOut() {
|
|
37
122
|
deleteSession();
|
|
38
123
|
return;
|
|
39
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Retrieves the current authenticated user's information from their session.
|
|
127
|
+
*
|
|
128
|
+
* Validates the session cookie and returns the decoded user token. If the session
|
|
129
|
+
* is invalid or expired, automatically cleans up the session cookie.
|
|
130
|
+
*
|
|
131
|
+
* @param checkRevoked - Whether to check if the user's token has been revoked (default: false)
|
|
132
|
+
* @returns Promise resolving to user data and error information
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* // Using guard clauses for clean error handling
|
|
137
|
+
* const { data: user, error } = await server.getUser();
|
|
138
|
+
* if (error) {
|
|
139
|
+
* console.error('Authentication error:', error);
|
|
140
|
+
* return redirect('/login');
|
|
141
|
+
* }
|
|
142
|
+
*
|
|
143
|
+
* if (!user) {
|
|
144
|
+
* console.log('No user session found');
|
|
145
|
+
* return redirect('/login');
|
|
146
|
+
* }
|
|
147
|
+
*
|
|
148
|
+
* // User is authenticated, proceed safely
|
|
149
|
+
* console.log('User ID:', user.sub);
|
|
150
|
+
* console.log('Email:', user.email);
|
|
151
|
+
* console.log('Email verified:', user.email_verified);
|
|
152
|
+
*
|
|
153
|
+
* // Check for revoked tokens in sensitive operations
|
|
154
|
+
* const { data: verifiedUser, error: revokeError } = await server.getUser(true);
|
|
155
|
+
* if (revokeError) return handleRevokedToken();
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
40
158
|
async function getUser(checkRevoked = false) {
|
|
41
159
|
const sessionCookie = await getSession(sessionName);
|
|
42
160
|
if (!sessionCookie) {
|
|
@@ -65,6 +183,47 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
65
183
|
error: null,
|
|
66
184
|
};
|
|
67
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Generates a Google OAuth login URL for user authentication.
|
|
188
|
+
*
|
|
189
|
+
* Automatically clears any existing session before generating the URL to ensure
|
|
190
|
+
* a clean authentication flow. The generated URL will redirect users to Google's
|
|
191
|
+
* OAuth consent screen.
|
|
192
|
+
*
|
|
193
|
+
* @param redirect_uri - The URI to redirect to after Google authentication (must be registered in Google Console)
|
|
194
|
+
* @param path - Additional path parameter for the OAuth flow state management
|
|
195
|
+
* @returns Promise resolving to the Google OAuth login URL
|
|
196
|
+
*
|
|
197
|
+
* @throws {Error} If Google provider is not configured in the providers config
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* // Basic usage with guard clause
|
|
202
|
+
* try {
|
|
203
|
+
* const loginUrl = await server.getGoogleLoginURL(
|
|
204
|
+
* 'https://yourapp.com/auth/callback',
|
|
205
|
+
* '/dashboard'
|
|
206
|
+
* );
|
|
207
|
+
* return redirect(loginUrl);
|
|
208
|
+
* } catch (error) {
|
|
209
|
+
* console.error('Google OAuth not configured:', error);
|
|
210
|
+
* return errorResponse('OAuth unavailable');
|
|
211
|
+
* }
|
|
212
|
+
*
|
|
213
|
+
* // In a route handler
|
|
214
|
+
* export async function GET(request: Request) {
|
|
215
|
+
* const url = new URL(request.url);
|
|
216
|
+
* const returnTo = url.searchParams.get('returnTo') || '/dashboard';
|
|
217
|
+
*
|
|
218
|
+
* const loginUrl = await server.getGoogleLoginURL(
|
|
219
|
+
* `${url.origin}/auth/callback`,
|
|
220
|
+
* returnTo
|
|
221
|
+
* );
|
|
222
|
+
*
|
|
223
|
+
* return redirect(loginUrl);
|
|
224
|
+
* }
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
68
227
|
async function getGoogleLoginURL(redirect_uri, path) {
|
|
69
228
|
deleteSession();
|
|
70
229
|
if (!providers.google) {
|
|
@@ -73,6 +232,56 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
73
232
|
const { client_id } = providers.google;
|
|
74
233
|
return createGoogleOAuthLoginUrl(redirect_uri, path, client_id);
|
|
75
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Completes Google OAuth authentication by exchanging an authorization code for a session.
|
|
237
|
+
*
|
|
238
|
+
* This method should be called in your OAuth callback handler to complete the authentication
|
|
239
|
+
* flow initiated by getGoogleLoginURL. It exchanges the authorization code for tokens,
|
|
240
|
+
* creates a Firebase session, and sets the session cookie.
|
|
241
|
+
*
|
|
242
|
+
* @param code - The authorization code received from Google OAuth callback
|
|
243
|
+
* @param redirect_uri - The redirect URI used in the OAuth flow (must match the one used in getGoogleLoginURL)
|
|
244
|
+
* @returns Promise resolving to success/error information
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* // In your OAuth callback handler with guard clauses
|
|
249
|
+
* export async function GET(request: Request) {
|
|
250
|
+
* const url = new URL(request.url);
|
|
251
|
+
* const code = url.searchParams.get('code');
|
|
252
|
+
* const state = url.searchParams.get('state');
|
|
253
|
+
*
|
|
254
|
+
* // Guard clauses for validation
|
|
255
|
+
* if (!code) {
|
|
256
|
+
* console.error('No authorization code received');
|
|
257
|
+
* return redirect('/login?error=no_code');
|
|
258
|
+
* }
|
|
259
|
+
*
|
|
260
|
+
* const { error } = await server.signInWithGoogleWithCode(
|
|
261
|
+
* code,
|
|
262
|
+
* `${url.origin}/auth/callback`
|
|
263
|
+
* );
|
|
264
|
+
*
|
|
265
|
+
* if (error) {
|
|
266
|
+
* console.error('Sign in failed:', error.message);
|
|
267
|
+
* return redirect('/login?error=auth_failed');
|
|
268
|
+
* }
|
|
269
|
+
*
|
|
270
|
+
* // Success - redirect to protected area
|
|
271
|
+
* const redirectTo = state || '/dashboard';
|
|
272
|
+
* return redirect(redirectTo);
|
|
273
|
+
* }
|
|
274
|
+
*
|
|
275
|
+
* // Error handling with specific error types
|
|
276
|
+
* const { error } = await server.signInWithGoogleWithCode(code, redirectUri);
|
|
277
|
+
* if (error?.message.includes('provider not configured')) {
|
|
278
|
+
* return handleConfigError();
|
|
279
|
+
* }
|
|
280
|
+
* if (error?.message.includes('invalid_grant')) {
|
|
281
|
+
* return handleExpiredCode();
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
76
285
|
async function signInWithGoogleWithCode(code, redirect_uri) {
|
|
77
286
|
if (!providers.google) {
|
|
78
287
|
return {
|
|
@@ -93,7 +302,6 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
93
302
|
}
|
|
94
303
|
const { data: signInData, error: signInError } = await auth.signInWithProvider(exchangeData.id_token, redirect_uri);
|
|
95
304
|
if (signInError) {
|
|
96
|
-
console.error(JSON.stringify(signInError));
|
|
97
305
|
return {
|
|
98
306
|
data: null,
|
|
99
307
|
error: signInError,
|
|
@@ -123,6 +331,48 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
123
331
|
error: null,
|
|
124
332
|
};
|
|
125
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Generates a fresh Firebase access token for the currently authenticated user.
|
|
336
|
+
*
|
|
337
|
+
* This method creates new Firebase client tokens that can be used for authenticated
|
|
338
|
+
* requests to Firebase services from the client-side. The tokens are generated using
|
|
339
|
+
* the user's server-side session.
|
|
340
|
+
*
|
|
341
|
+
* @returns Promise resolving to token data (accessToken, refreshToken, etc.) and error information
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* // Using guard clauses for clean token handling
|
|
346
|
+
* const { data: tokenData, error } = await server.getToken();
|
|
347
|
+
* if (error) {
|
|
348
|
+
* console.error('Token generation failed:', error.message);
|
|
349
|
+
* return redirect('/login');
|
|
350
|
+
* }
|
|
351
|
+
*
|
|
352
|
+
* if (!tokenData) {
|
|
353
|
+
* console.log('No user session for token generation');
|
|
354
|
+
* return redirect('/login');
|
|
355
|
+
* }
|
|
356
|
+
*
|
|
357
|
+
* // Tokens are ready for client use
|
|
358
|
+
* const response = {
|
|
359
|
+
* accessToken: tokenData.accessToken,
|
|
360
|
+
* refreshToken: tokenData.refreshToken,
|
|
361
|
+
* expiresIn: tokenData.expiresIn
|
|
362
|
+
* };
|
|
363
|
+
*
|
|
364
|
+
* return json(response);
|
|
365
|
+
*
|
|
366
|
+
* // Using tokens for Firebase client initialization
|
|
367
|
+
* const auth = getAuth(app);
|
|
368
|
+
* await signInWithCustomToken(auth, tokenData.accessToken);
|
|
369
|
+
*
|
|
370
|
+
* // Guard against token refresh failures
|
|
371
|
+
* if (tokenData.expiresIn < 300) { // Less than 5 minutes
|
|
372
|
+
* console.warn('Token expires soon, consider refreshing');
|
|
373
|
+
* }
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
126
376
|
async function getToken() {
|
|
127
377
|
const { data: verifiedToken, error: verifyError } = await getUser();
|
|
128
378
|
if (verifyError) {
|
|
@@ -152,7 +402,6 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
152
402
|
}
|
|
153
403
|
const { data: signInData, error: signInError } = await auth.signInWithCustomToken(signJWTData);
|
|
154
404
|
if (signInError) {
|
|
155
|
-
console.error(signInError);
|
|
156
405
|
return {
|
|
157
406
|
data: null,
|
|
158
407
|
error: signInError,
|
|
@@ -169,6 +418,18 @@ export function createFirebaseEdgeServer({ serviceAccount, firebaseConfig, provi
|
|
|
169
418
|
error: null,
|
|
170
419
|
};
|
|
171
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Returns the complete Firebase Edge Server API with all authentication methods.
|
|
423
|
+
*
|
|
424
|
+
* @returns Object containing:
|
|
425
|
+
* - `auth`: Firebase Auth instance for client-side operations
|
|
426
|
+
* - `adminAuth`: Firebase Admin Auth instance for server-side operations
|
|
427
|
+
* - `signOut`: Function to sign out the current user
|
|
428
|
+
* - `getUser`: Function to get current user information with optional revocation checking
|
|
429
|
+
* - `getGoogleLoginURL`: Function to generate Google OAuth login URL
|
|
430
|
+
* - `signInWithGoogleWithCode`: Function to complete Google OAuth flow
|
|
431
|
+
* - `getToken`: Function to get fresh Firebase tokens for client-side usage
|
|
432
|
+
*/
|
|
172
433
|
return {
|
|
173
434
|
auth,
|
|
174
435
|
adminAuth,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-edge-server.js","sourceRoot":"","sources":["../src/firebase-edge-server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EACH,yBAAyB,EACzB,4BAA4B,GAC/B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,oBAAoB,GAAG,WAAW,CAAC;AAEzC,MAAM,cAAc,GAAG;IACnB,QAAQ,EAAE,IAAI;IACd,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,KAAK;IACf,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI;CACjB,CAAC;AAEnB,MAAM,CAAC,MAAM,iCAAiC,
|
|
1
|
+
{"version":3,"file":"firebase-edge-server.js","sourceRoot":"","sources":["../src/firebase-edge-server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-admin-edge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "A demo package for Total TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"demo",
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
"dev": "vitest",
|
|
40
40
|
"clean": "rimraf dist",
|
|
41
41
|
"local-release": "npm run format && changeset version && changeset publish",
|
|
42
|
-
"prepublishOnly": "npm run ci"
|
|
42
|
+
"prepublishOnly": "npm run ci",
|
|
43
|
+
"changeset": "changeset",
|
|
44
|
+
"changeset:version": "changeset version",
|
|
45
|
+
"changeset:publish": "changeset publish"
|
|
43
46
|
}
|
|
44
47
|
}
|