setup firebase custom token

This commit is contained in:
talksik
2026-04-16 11:26:11 -07:00
parent 28b1ff542b
commit 41fe404d0a
20 changed files with 494 additions and 31 deletions
+9
View File
@@ -5,6 +5,7 @@ import {
BillingStatusSchema,
CheckoutSessionResponseSchema,
DepotObjectSchema,
FirebaseTokenResponseSchema,
GetLivekitTokenResponseSchema,
HumanSchema,
ListInvitationsResponseSchema,
@@ -121,6 +122,14 @@ class ApiClient {
await this.requestVoid("POST", "/auth/sign-out");
}
async getFirebaseToken() {
return this.request(
FirebaseTokenResponseSchema,
"POST",
"/auth/firebase-token",
);
}
// TODO: security: require passing in the particle id once api deprecates this
async getParticleDownloadUrl(objectId: string): Promise<string> {
const response = await this.fetch(
+5
View File
@@ -263,6 +263,11 @@ export const SignInResponseSchema = z.object({
});
export type SignInResponse = z.infer<typeof SignInResponseSchema>;
export const FirebaseTokenResponseSchema = z.object({
token: z.string(),
});
export type FirebaseTokenResponse = z.infer<typeof FirebaseTokenResponseSchema>;
// --- Billing types ---
export const BillingCadenceSchema = z.enum(["monthly", "annual"]);
+3
View File
@@ -1,9 +1,12 @@
import { initializeApp } from 'firebase/app';
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import { appConfig } from "@/config/env";
export const firebaseApp = initializeApp(appConfig.firebase);
export const firebaseAuth = getAuth(firebaseApp);
export const firestoreDb = getFirestore(firebaseApp);
// simplifying setup to debug production issues
// export const firestoreDb = initializeFirestore(firebaseApp,
+16
View File
@@ -1,8 +1,19 @@
import { create } from "zustand";
import { signInWithCustomToken, signOut as firebaseSignOut } from "firebase/auth";
import { apiClient, ApiError } from "@/api/client";
import type { Human } from "@/api/types";
import { firebaseAuth } from "@/firebase";
import { useSessionStore } from "./session-store";
async function signInToFirebase() {
try {
const { token } = await apiClient.getFirebaseToken();
await signInWithCustomToken(firebaseAuth, token);
} catch (e) {
console.error("Failed to sign in to Firebase", e);
}
}
type AuthStatus = "idle" | "restoring" | "unauthenticated" | "authenticated";
interface AuthState {
@@ -37,6 +48,7 @@ export const useAuthStore = create<AuthState>((set) => ({
set({ status: "restoring" });
try {
const user = await apiClient.me();
await signInToFirebase();
set({ status: "authenticated", user });
} catch {
useSessionStore.getState().clearToken();
@@ -63,6 +75,7 @@ export const useAuthStore = create<AuthState>((set) => ({
try {
const { human, token } = await apiClient.signIn({ email, code });
useSessionStore.getState().setToken(token);
await signInToFirebase();
set({ status: "authenticated", user: human });
} catch (e) {
const message =
@@ -81,6 +94,9 @@ export const useAuthStore = create<AuthState>((set) => ({
} catch {
// Best-effort — sign out locally regardless
} finally {
await firebaseSignOut(firebaseAuth).catch((e) =>
console.error("Firebase sign-out failed", e),
);
useSessionStore.getState().clearToken();
set({
status: "unauthenticated",