This repo contains an example todo app that showcases how to implement authentication in a local-first app using the following technologies:
- Fullstack React: TanStack Start
- Data layer: LiveStore
- Authentication: BetterAuth & BetterAuth Cloudflare Plugin
- User credential storage: Cloudflare D1
- Backend syncing: Cloudflare Workers & Durable Objects
After authentication, every user of the app receives their own local instance of a LiveStore DB that they can use locally on their machine, ensuring full isolation as well as offline access.
git clone git@github.com:nikolasburk/livestore-tanstack-cloudflare-auth-example.git
cd livestore-tanstack-cloudflare-auth-example
pnpm install
Rename .env.example to .env and update the env vars in that file as follows.
Create a D1 database and set the env vars in .env as described here. Here are some real-looking sample values:
# replace these values with your own
CLOUDFLARE_ACCOUNT_ID=6cfd2fa210ebf08b224c0f39248e1c05
CLOUDFLARE_DATABASE_ID=d5b3d994-1a05-43cb-8cd5-b668b73d0d53
CLOUDFLARE_D1_TOKEN=XDPhgV57Tr-zljPhXdsyiuAG4V_gjFq1b8FNiZoJSet the BETTER_AUTH_SECRET to a value of your choice. You can also generate a secret here by clicking on the Generate Secret button. Here are some real-looking sample values:
# replace these values with your own
BETTER_AUTH_SECRET=i2zaoTAZz0yXjfHlTXIhAxWlERrXoCCn
BETTER_AUTH_URL=http://localhost:3000 # Base URL of your appNow you can run the app with:
pnpm dev
Here are some things you can do to test the app:
- Sign up with a new user
- Open a new browser window -> the same user should be logged in automatically in both windows now
- Create a todo in one window -> the second window should update instantly and show the same todo
- Open an incognito window and sign up with a different user
- Open another incognito window -> the second user should be logged in automatically in both incognito windows now
- Create a todo in one incognito window -> the second incognito window should update instantly and show the same todo
To deploy the app, you can run:
pnpm run deploy
The auth mechanism currently isn't fully safe:
- Anyone could connect to another user's sync endpoint if they knew/guessed the
storeId(which is not too difficult) - No verification that sync operations (
onPush/onPull) are from an authenticated user
The solution will be to add an auth token to the WebSockets that are doing the syncing, something similar to this:
- Extract the auth token from the WebSocket connection (headers or query params)
- Verify the token using BetterAuth in the sync handlers
- Ensure the authenticated user matches the
storeId/userIdassociated with the sync operation
