@mastra/auth-firebase 0.10.2 → 0.10.3-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +15 -2
- package/.turbo/turbo-build.log +0 -4
- package/eslint.config.js +0 -6
- package/src/index.test.ts +0 -157
- package/src/index.ts +0 -51
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -17
- package/vitest.config.ts +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @mastra/auth-firebase
|
|
2
2
|
|
|
3
|
+
## 0.10.3-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#7343](https://github.com/mastra-ai/mastra/pull/7343) [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e) Thanks [@LekoArts](https://github.com/LekoArts)! - Update the `package.json` file to include additional fields like `repository`, `homepage` or `files`.
|
|
8
|
+
|
|
3
9
|
## 0.10.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/auth-firebase",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3-alpha.0",
|
|
4
4
|
"description": "Mastra Firebase Auth integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,9 +29,22 @@
|
|
|
29
29
|
"typescript": "^5.8.3",
|
|
30
30
|
"vitest": "^3.2.4",
|
|
31
31
|
"@internal/lint": "0.0.34",
|
|
32
|
-
"@mastra/core": "0.15.
|
|
32
|
+
"@mastra/core": "0.15.3-alpha.5",
|
|
33
33
|
"@internal/types-builder": "0.0.9"
|
|
34
34
|
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"CHANGELOG.md"
|
|
38
|
+
],
|
|
39
|
+
"homepage": "https://mastra.ai",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/mastra-ai/mastra.git",
|
|
43
|
+
"directory": "auth/firebase"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/mastra-ai/mastra/issues"
|
|
47
|
+
},
|
|
35
48
|
"scripts": {
|
|
36
49
|
"build": "tsup --silent --config tsup.config.ts",
|
|
37
50
|
"build:watch": "tsup --watch --silent --config tsup.config.ts",
|
package/.turbo/turbo-build.log
DELETED
package/eslint.config.js
DELETED
package/src/index.test.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import admin from 'firebase-admin';
|
|
2
|
-
import { getFirestore } from 'firebase-admin/firestore';
|
|
3
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
4
|
-
import { MastraAuthFirebase } from './index';
|
|
5
|
-
|
|
6
|
-
// Mock Firebase Admin
|
|
7
|
-
vi.mock('firebase-admin', () => ({
|
|
8
|
-
default: {
|
|
9
|
-
apps: [],
|
|
10
|
-
initializeApp: vi.fn(),
|
|
11
|
-
auth: vi.fn(() => ({
|
|
12
|
-
verifyIdToken: vi.fn(),
|
|
13
|
-
})),
|
|
14
|
-
credential: {
|
|
15
|
-
cert: vi.fn(() => 'mock-credential'),
|
|
16
|
-
applicationDefault: vi.fn(() => 'mock-default-credential'),
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
// Mock Firestore
|
|
22
|
-
vi.mock('firebase-admin/firestore', () => ({
|
|
23
|
-
getFirestore: vi.fn(() => ({
|
|
24
|
-
doc: vi.fn(() => ({
|
|
25
|
-
get: vi.fn(),
|
|
26
|
-
})),
|
|
27
|
-
})),
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
describe('MastraAuthFirebase', () => {
|
|
31
|
-
const mockServiceAccount = 'mock-service-account';
|
|
32
|
-
const mockDatabaseId = 'mock-database-id';
|
|
33
|
-
const mockToken = 'mock-token';
|
|
34
|
-
const mockUserId = 'mock-user-id';
|
|
35
|
-
|
|
36
|
-
beforeEach(() => {
|
|
37
|
-
vi.clearAllMocks();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe('initialization', () => {
|
|
41
|
-
it('should initialize with provided options', () => {
|
|
42
|
-
const auth = new MastraAuthFirebase({
|
|
43
|
-
serviceAccount: mockServiceAccount,
|
|
44
|
-
databaseId: mockDatabaseId,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
expect(auth).toBeInstanceOf(MastraAuthFirebase);
|
|
48
|
-
expect(admin.initializeApp).toHaveBeenCalledWith({
|
|
49
|
-
credential: 'mock-credential',
|
|
50
|
-
});
|
|
51
|
-
expect(admin.credential.cert).toHaveBeenCalledWith(mockServiceAccount);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should initialize with environment variables', () => {
|
|
55
|
-
process.env.FIREBASE_SERVICE_ACCOUNT = mockServiceAccount;
|
|
56
|
-
process.env.FIRESTORE_DATABASE_ID = mockDatabaseId;
|
|
57
|
-
|
|
58
|
-
const auth = new MastraAuthFirebase();
|
|
59
|
-
|
|
60
|
-
expect(auth).toBeInstanceOf(MastraAuthFirebase);
|
|
61
|
-
expect(admin.initializeApp).toHaveBeenCalledWith({
|
|
62
|
-
credential: 'mock-credential',
|
|
63
|
-
});
|
|
64
|
-
expect(admin.credential.cert).toHaveBeenCalledWith(mockServiceAccount);
|
|
65
|
-
|
|
66
|
-
delete process.env.FIREBASE_SERVICE_ACCOUNT;
|
|
67
|
-
delete process.env.FIRESTORE_DATABASE_ID;
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('authenticateToken', () => {
|
|
72
|
-
it('should verify and return decoded token', async () => {
|
|
73
|
-
const mockDecodedToken = { uid: mockUserId };
|
|
74
|
-
const mockVerifyIdToken = vi.fn().mockResolvedValue(mockDecodedToken);
|
|
75
|
-
|
|
76
|
-
(admin.auth as any).mockReturnValue({
|
|
77
|
-
verifyIdToken: mockVerifyIdToken,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const auth = new MastraAuthFirebase();
|
|
81
|
-
const result = await auth.authenticateToken(mockToken);
|
|
82
|
-
|
|
83
|
-
expect(mockVerifyIdToken).toHaveBeenCalledWith(mockToken);
|
|
84
|
-
expect(result).toEqual(mockDecodedToken);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should return null when token verification fails', async () => {
|
|
88
|
-
const mockVerifyIdToken = vi.fn().mockRejectedValue(new Error('Invalid token'));
|
|
89
|
-
|
|
90
|
-
(admin.auth as any).mockReturnValue({
|
|
91
|
-
verifyIdToken: mockVerifyIdToken,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const auth = new MastraAuthFirebase();
|
|
95
|
-
const result = await auth.authenticateToken(mockToken).catch(() => null);
|
|
96
|
-
|
|
97
|
-
expect(mockVerifyIdToken).toHaveBeenCalledWith(mockToken);
|
|
98
|
-
expect(result).toBeNull();
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('authorizeUser', () => {
|
|
103
|
-
it('should return true when user has access', async () => {
|
|
104
|
-
const mockUser = { uid: mockUserId };
|
|
105
|
-
const mockUserAccessData = { someData: 'value' };
|
|
106
|
-
const mockGet = vi.fn().mockResolvedValue({ data: () => mockUserAccessData });
|
|
107
|
-
const mockDoc = vi.fn().mockReturnValue({ get: mockGet });
|
|
108
|
-
|
|
109
|
-
(getFirestore as any).mockReturnValue({
|
|
110
|
-
doc: mockDoc,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const auth = new MastraAuthFirebase();
|
|
114
|
-
const result = await auth.authorizeUser(mockUser as any);
|
|
115
|
-
|
|
116
|
-
expect(mockDoc).toHaveBeenCalledWith(`/user_access/${mockUserId}`);
|
|
117
|
-
expect(result).toBe(true);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should return false when user has no access', async () => {
|
|
121
|
-
const mockUser = { uid: mockUserId };
|
|
122
|
-
const mockGet = vi.fn().mockResolvedValue({ data: () => null });
|
|
123
|
-
const mockDoc = vi.fn().mockReturnValue({ get: mockGet });
|
|
124
|
-
|
|
125
|
-
(getFirestore as any).mockReturnValue({
|
|
126
|
-
doc: mockDoc,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
const auth = new MastraAuthFirebase();
|
|
130
|
-
const result = await auth.authorizeUser(mockUser as any);
|
|
131
|
-
|
|
132
|
-
expect(mockDoc).toHaveBeenCalledWith(`/user_access/${mockUserId}`);
|
|
133
|
-
expect(result).toBe(false);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('can be overridden with custom authorization logic', async () => {
|
|
138
|
-
const firebase = new MastraAuthFirebase({
|
|
139
|
-
async authorizeUser(user: any): Promise<boolean> {
|
|
140
|
-
// Custom authorization logic that checks for specific permissions
|
|
141
|
-
return user?.permissions?.includes('admin') ?? false;
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Test with admin user
|
|
146
|
-
const adminUser = { sub: 'user123', permissions: ['admin'] } as unknown as DecodedIdToken;
|
|
147
|
-
expect(await firebase.authorizeUser(adminUser)).toBe(true);
|
|
148
|
-
|
|
149
|
-
// Test with non-admin user
|
|
150
|
-
const regularUser = { sub: 'user456', permissions: ['read'] };
|
|
151
|
-
expect(await firebase.authorizeUser(regularUser)).toBe(false);
|
|
152
|
-
|
|
153
|
-
// Test with user without permissions
|
|
154
|
-
const noPermissionsUser = { sub: 'user789' };
|
|
155
|
-
expect(await firebase.authorizeUser(noPermissionsUser)).toBe(false);
|
|
156
|
-
});
|
|
157
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { MastraAuthProviderOptions } from '@mastra/core/server';
|
|
2
|
-
import { MastraAuthProvider } from '@mastra/core/server';
|
|
3
|
-
|
|
4
|
-
import admin from 'firebase-admin';
|
|
5
|
-
import { getFirestore } from 'firebase-admin/firestore';
|
|
6
|
-
|
|
7
|
-
type FirebaseUser = admin.auth.DecodedIdToken;
|
|
8
|
-
|
|
9
|
-
interface MastraAuthFirebaseOptions extends MastraAuthProviderOptions<FirebaseUser> {
|
|
10
|
-
databaseId?: string;
|
|
11
|
-
serviceAccount?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class MastraAuthFirebase extends MastraAuthProvider<FirebaseUser> {
|
|
15
|
-
private serviceAccount: string | undefined;
|
|
16
|
-
private databaseId: string | undefined;
|
|
17
|
-
|
|
18
|
-
constructor(options?: MastraAuthFirebaseOptions) {
|
|
19
|
-
super({ name: options?.name ?? 'firebase' });
|
|
20
|
-
|
|
21
|
-
this.serviceAccount = options?.serviceAccount ?? process.env.FIREBASE_SERVICE_ACCOUNT;
|
|
22
|
-
this.databaseId = options?.databaseId ?? process.env.FIRESTORE_DATABASE_ID ?? process.env.FIREBASE_DATABASE_ID;
|
|
23
|
-
|
|
24
|
-
if (!admin.apps.length) {
|
|
25
|
-
admin.initializeApp({
|
|
26
|
-
credential: this.serviceAccount
|
|
27
|
-
? admin.credential.cert(this.serviceAccount)
|
|
28
|
-
: admin.credential.applicationDefault(),
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this.registerOptions(options);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async authenticateToken(token: string): Promise<FirebaseUser | null> {
|
|
36
|
-
const decoded = await admin.auth().verifyIdToken(token);
|
|
37
|
-
return decoded;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async authorizeUser(user: FirebaseUser) {
|
|
41
|
-
const db = this.databaseId ? getFirestore(this.databaseId) : getFirestore();
|
|
42
|
-
const userAccess = await db.doc(`/user_access/${user.uid}`).get();
|
|
43
|
-
const userAccessData = userAccess.data();
|
|
44
|
-
|
|
45
|
-
if (!userAccessData) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
}
|
package/tsconfig.build.json
DELETED
package/tsconfig.json
DELETED
package/tsup.config.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { generateTypes } from '@internal/types-builder';
|
|
2
|
-
import { defineConfig } from 'tsup';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
entry: ['src/index.ts'],
|
|
6
|
-
format: ['esm', 'cjs'],
|
|
7
|
-
clean: true,
|
|
8
|
-
dts: false,
|
|
9
|
-
splitting: true,
|
|
10
|
-
treeshake: {
|
|
11
|
-
preset: 'smallest',
|
|
12
|
-
},
|
|
13
|
-
sourcemap: true,
|
|
14
|
-
onSuccess: async () => {
|
|
15
|
-
await generateTypes(process.cwd());
|
|
16
|
-
},
|
|
17
|
-
});
|