Your personalized daily.dev feed as private RSS 2.0 and JSON Feed URLs for any reader. People sign in with daily.dev, approve read-only access, and get a private page with their feed URLs. No API token to copy.
Built on the daily.dev public API with Sign in with daily.dev. Next.js App Router running on vinext, deployed to Cloudflare Workers, with tokens and rendered feeds in Workers KV.
GET /api/auth/loginstarts the OAuth 2.1 flow (authorization code + PKCE, confidential client, scopesopenid profile offline_access read).GET /api/auth/callbackexchanges the code, fetches/public/v1/profile, creates an unguessable feed id and stores the tokens, encrypted with AES-256-GCM, in KV.GET /f/<id>is the private page with feed URLs and a delete button.GET /f/<id>/<source>.<xml|json>renders the feed. Onlyforyouis enabled.popular,discussedandbookmarksare implemented too; add them toENABLED_FEED_SOURCESinlib/feeds.tsto offer them. Enabling more than one makes concurrent token refreshes likely, see the security notes.
Feeds are rendered from a KV cache that lives FEED_CACHE_SECONDS (8 hours by default). Reader polling never reaches daily.dev more often than that, so one feed costs about 90 API requests a month, inside the free quota of 200 requests per 30 days. A lock prevents two concurrent polls from refreshing the token twice (refresh tokens rotate on every use).
When the refresh token has expired because nobody fetched the feed for a while, the feed keeps returning 200 with a single "reconnect" item instead of breaking, and the feed page offers a re-sign-in that keeps the same URLs.
- Create an OAuth app at daily.dev → Settings → API → OAuth apps with the redirect URI
http://localhost:3006/api/auth/callback. cp .env.example .env.local, fill in the client id and secret, andTOKEN_ENCRYPTION_KEY=$(openssl rand -base64 32).pnpm install && pnpm run dev, then open http://localhost:3006.
The dev server runs the app inside workerd, the Workers runtime, with a local KV namespace. No Cloudflare account is needed to develop.
- Sign in with
pnpm exec cf auth login, or setCLOUDFLARE_API_TOKEN(the Edit Cloudflare Workers template) in CI. - Set
CLOUDFLARE_ACCOUNT_ID, or addaccountIdat the top level ofcloudflare.config.ts. - Create the KV namespace with
pnpm exec cf kv namespaces createand put its id inFEEDS: bindings.kv({ id: "<id>" }). - Set the secrets declared in
cloudflare.config.tswithpnpm exec cf workers secrets update:DAILY_CLIENT_ID,DAILY_CLIENT_SECRET,TOKEN_ENCRYPTION_KEY,APP_URLand, if you don't use production daily.dev,DAILY_API_URL. - Add
<APP_URL>/api/auth/callbackto your OAuth app's redirect URIs on daily.dev. pnpm run deploy.
| Variable | Default | What it does |
|---|---|---|
FEED_CACHE_SECONDS |
28800 |
How long a rendered feed is served from cache. Lower it for Plus users, who have no monthly quota. |
FEED_ITEMS |
30 |
Posts per feed, 1 to 50. |
DAILY_API_URL |
https://api.daily.dev |
API origin. |
- The client secret and the encryption key never leave the server.
- Access and refresh tokens are encrypted at rest. Rotating
TOKEN_ENCRYPTION_KEYinvalidates every stored feed; people reconnect from their feed page. - The refresh lock is best effort: KV has no atomic set-if-absent, so two refreshes landing in the same second can both go through. daily.dev then treats the reused refresh token as stolen and revokes all of the person's tokens for the app, so the feed shows the reconnect item until they sign in again. With one feed per person this needs the same feed polled twice at once, for example from two readers.
- Feed URLs are bearer secrets. Responses are
Cache-Control: privateandX-Robots-Tag: noindex. - Only the
readscope is requested; the app can't change anything on a daily.dev account. - People can revoke access from daily.dev → Settings → API → Connected apps, or delete their feeds from the feed page, which removes the stored tokens immediately.