fix: use getAuthHeader in createCustomer for API key auth support (#8983)

## Summary

Re-apply the fix from PR #8408 that was accidentally reverted by PR
#8508 — `createCustomer` must use `getAuthHeader()` (not
`getFirebaseAuthHeader()`) so API key authentication works.

## Changes

- **What**: Changed `createCustomer` in `firebaseAuthStore.ts` to use
`getAuthHeader()` which falls back through workspace token → Firebase
token → API key. Added regression tests covering API key auth, Firebase
auth, and no-auth paths.

## Review Focus

This is the same one-line fix from #8408. PR #8508 ("Feat/workspaces 6
billing") overwrote it during merge because it was branched before #8408
landed. The regression test should prevent this from happening again.

Fixes COM-15060

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8983-fix-use-getAuthHeader-in-createCustomer-for-API-key-auth-support-30c6d73d365081c2aab6d5defa5298d6)
by [Unito](https://www.unito.io)
This commit is contained in:
Christian Byrne
2026-02-18 20:47:12 -08:00
committed by GitHub
parent 8ab9a7b887
commit cc2c10745b
2 changed files with 59 additions and 1 deletions

View File

@@ -99,6 +99,19 @@ vi.mock('@/stores/toastStore', () => ({
// Mock useDialogService
vi.mock('@/services/dialogService')
// Mock apiKeyAuthStore
const mockApiKeyGetAuthHeader = vi.fn().mockReturnValue(null)
vi.mock('@/stores/apiKeyAuthStore', () => ({
useApiKeyAuthStore: () => ({
getAuthHeader: mockApiKeyGetAuthHeader,
getApiKey: vi.fn(),
currentUser: null,
isAuthenticated: false,
storeApiKey: vi.fn(),
clearStoredApiKey: vi.fn()
})
}))
describe('useFirebaseAuthStore', () => {
let store: ReturnType<typeof useFirebaseAuthStore>
let authStateCallback: (user: User | null) => void
@@ -164,6 +177,9 @@ describe('useFirebaseAuthStore', () => {
// Reset and set up getIdToken mock
mockUser.getIdToken.mockReset()
mockUser.getIdToken.mockResolvedValue('mock-id-token')
// Default: no API key auth
mockApiKeyGetAuthHeader.mockReturnValue(null)
})
describe('token refresh events', () => {
@@ -628,4 +644,46 @@ describe('useFirebaseAuthStore', () => {
await expect(store.accessBillingPortal()).rejects.toThrow()
})
})
describe('createCustomer', () => {
it('should succeed with API key auth when no Firebase user is present', async () => {
authStateCallback(null)
mockApiKeyGetAuthHeader.mockReturnValue({ 'X-API-KEY': 'test-api-key' })
const result = await store.createCustomer()
expect(mockFetch).toHaveBeenCalledWith(
expect.stringContaining('/customers'),
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({
'X-API-KEY': 'test-api-key'
})
})
)
expect(result).toEqual({ id: 'test-customer-id' })
})
it('should use Firebase token when Firebase user is present', async () => {
const result = await store.createCustomer()
expect(mockFetch).toHaveBeenCalledWith(
expect.stringContaining('/customers'),
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({
Authorization: 'Bearer mock-id-token'
})
})
)
expect(result).toEqual({ id: 'test-customer-id' })
})
it('should throw when no auth method is available', async () => {
authStateCallback(null)
mockApiKeyGetAuthHeader.mockReturnValue(null)
await expect(store.createCustomer()).rejects.toThrow()
})
})
})

View File

@@ -277,7 +277,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
}
const createCustomer = async (): Promise<CreateCustomerResponse> => {
const authHeader = await getFirebaseAuthHeader()
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
}