setup firebase custom token
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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"]);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user