-
Notifications
You must be signed in to change notification settings - Fork 37
feat: Add Fireproof Dashboard POC with tenant/ledger management #659
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jchris
wants to merge
30
commits into
main
Choose a base branch
from
jchris/fireproof-dashboard-api
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
8bb7f91
feat: add Fireproof Dashboard with tenant and ledger management using…
jchris 9bb21f5
debug log
jchris 41e6228
feat: Improve error message for JWKS token verification failures
jchris efcd5f4
feat: Parse and check token expiry before use
jchris 6d7ab15
feat: Warn on token issuer mismatch
jchris d55e2a6
feat: Clarify backend config issue in warning
jchris 2d42fef
feat: Update auth mismatch warning with backend type limitation
jchris 107238c
fix: Remove misleading auth type mismatch warning
jchris d28f13f
feat: Implement fp-cloud-jwt token exchange for DashboardApi
jchris 2de890c
fix: Correct DashboardApi initialization and token type for fp-cloud-jwt
jchris b2f74cc
fix: Wait for fp-cloud-jwt before fetching dashboard data
jchris 0a29543
feat: Log token header and audience for debugging
jchris 282a182
feat: Add explicit KID check for debugging
jchris f5693b1
docs: Add token auth exchange analysis for debugging
jchris 4978636
feat: Enhance logging to indicate query enablement
jchris ef01ee3
chore: Apply formatting changes from pnpm check
jchris 5947147
refactor: Revert auth exchange complexity and use Clerk token directly
jchris ff7144a
fix: Restore required fetch prop in DashboardApi config
jchris c50641f
fix: Attempt to set audience to 'fireproof' for Clerk token
jchris f20db4d
feat: Temporarily log Clerk JWT for debugging
jchris 449b91a
chore: Remove temporary debug logging
jchris a9e8786
format
jchris 6182f83
remove audience
jchris ff46a54
refactor: Simplify fireproof route to only call ensureUser
jchris 9e4ddf0
fix: Remove unsupported 'audience' from Clerk getToken call
jchris 3e7395d
fix: Remove unused useEffect import
jchris 1c47ff1
fix: Update CONNECT_API_URL to handle production and development envi…
jchris fc2e6b4
fix: Address PR feedback for fireproof dashboard route
jchris b8f02af
fix: Wrap fetch in arrow function to preserve context
jchris ebd9e03
fix: Update FireproofDashboard to include userId in ensureUser query …
jchris File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Token Auth & Exchange Flow Analysis | ||
|
|
||
| This document describes the current observed authentication flow and the specific failure point encountered when integrating the `vibes.diy` development environment with the Fireproof Connect backend. | ||
|
|
||
| ## The Goal | ||
|
|
||
| Authenticate a user on the `vibes.diy` local development environment using a **Clerk Development Instance** (`sincere-cheetah-30...`) and successfully exchange this token for a Fireproof Cloud token (`fp-cloud-jwt`) via the production Fireproof backend (`https://connect.fireproof.direct/api`). | ||
|
|
||
| ## The Flow | ||
|
|
||
| 1. **Client Authentication (Success)** | ||
| - The `vibes.diy` app uses `@clerk/clerk-react` to sign the user in. | ||
| - **Result:** A valid JWT is obtained. | ||
| - **Issuer (`iss`):** `https://sincere-cheetah-30.clerk.accounts.dev` | ||
| - **Key ID (`kid`):** `ins_35qNS5Jwyc7z4aJRBIS7o205yzb` | ||
| - **Algorithm:** `RS256` | ||
| - **Audience (`aud`):** `undefined` (No audience claim present). | ||
|
|
||
| 2. **Token Verification / Exchange Request (Failure)** | ||
| - The client calls `DashboardApi.getCloudSessionToken({})`. | ||
| - **Payload:** `{ auth: { type: "clerk", token: "..." } }` | ||
| - **Endpoint:** `PUT https://connect.fireproof.direct/api` | ||
|
|
||
| 3. **Backend Verification (Error)** | ||
| _ The backend receives the request and attempts to verify the token. | ||
| _ **Backend Configuration:** The backend is configured with `CLERK_PUB_JWT_URL` containing three issuers, including the development one: | ||
| _ `https://clerk.fireproof.direct` | ||
| _ `https://clerk.vibes.diy` | ||
| _ `https://sincere-cheetah-30.clerk.accounts.dev` | ||
| _ **Response:** HTTP 500 \* **Error Message:** | ||
| `json | ||
| { | ||
| "type": "error", | ||
| "message": "No well-known JWKS URL could verify the token:\n[ | ||
| { | ||
| "type": "error", | ||
| "error": { | ||
| "reason": "token-invalid-signature" | ||
| }, | ||
| "url": "https://clerk.fireproof.direct/.well-known/jwks.json" | ||
| }, | ||
| { | ||
| "type": "error", | ||
| "error": { | ||
| "reason": "token-invalid-signature" | ||
| }, | ||
| "url": "https://clerk.vibes.diy/.well-known/jwks.json" | ||
| }, | ||
| { | ||
| "type": "error", | ||
| "error": { | ||
| "reason": "token-invalid-signature" | ||
| }, | ||
| "url": "https://sincere-cheetah-30.clerk.accounts.dev/.well-known/jwks.json" | ||
| } | ||
| ]" | ||
| } | ||
| ` | ||
|
|
||
| ## Diagnosis Findings | ||
|
|
||
| - **✅ Issuer Match:** The client sends a token from `sincere-cheetah-30`. The backend _is_ attempting to verify against the corresponding JWKS URL. | ||
| - **✅ Key ID Match:** The client token has `kid: 'ins_35qNS5Jwyc7z4aJRBIS7o205yzb'`. The public JWKS at `https://sincere-cheetah-30.clerk.accounts.dev/.well-known/jwks.json` currently contains this exact key. | ||
| - **❌ Signature Verification Failure:** Despite the correct issuer and key ID, the backend reports `token-invalid-signature`. | ||
|
|
||
| ## Potential Root Causes for Review | ||
|
|
||
| 1. **Audience (`aud`) Validation:** | ||
| - The client token has **no `aud` claim**. | ||
| - Does the backend's `@hono/clerk-auth` middleware (or underlying `verifyToken` function) enforce a default audience check? If so, the lack of an audience would cause verification to fail even if the signature is valid. | ||
|
|
||
| 2. **Stale JWKS Cache:** | ||
| - Could the backend be caching an older version of the JWKS for `sincere-cheetah-30` that does not yet contain the key `ins_35qNS5Jwyc7z4aJRBIS7o205yzb`? | ||
| - _Note: This is less likely if this is a stable dev instance, but possible if keys were recently rotated._ | ||
|
|
||
| 3. **Crypto/Environment Mismatch:** | ||
| - Is the backend environment (e.g., Cloudflare Workers) correctly handling the RS256 signature verification for this specific key? | ||
|
|
||
| ## Request for Engineering Team | ||
|
|
||
| Please verify if the Fireproof backend enforces an **Audience (`aud`) claim** on Clerk tokens. If so, what audience value is expected? We may need to configure our Clerk development instance to include this audience in its issued tokens. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The global
QueryClientinstance is created at module scope with default options, which is good, but there is no strategy for cache invalidation on auth changes. Because theQueryClientProviderwraps the entire app, when a user signs out and another user signs in, any user-scoped queries (like your dashboard data) will remain in the cache unless keys or session boundaries are managed explicitly.Especially when combined with static query keys, this can create subtle cross-user data exposure within the same browser session. Even if you fix the keys, it's generally a good idea to reset or partially clear the query cache on auth state transitions for user-scoped data.
Suggestion
Consider either scoping the
QueryClientto the current auth session or listening to Clerk auth events to clear user-specific queries on sign-out:Alternatively, if you segment query keys by
userId, target only those keys withremoveQueries. This keeps the global cache while preventing leakage of user-specific data across sessions. Reply with "@CharlieHelps yes please" if you'd like me to add a commit wiring this up with Clerk auth events.