Skip to content

feat: sign in and authorize access keys through Tempo ID with accounts@alpha - #108

Draft
jxom wants to merge 4 commits into
mainfrom
feat/tempo-id-sign-in
Draft

jxom wants to merge 4 commits into
mainfrom
feat/tempo-id-sign-in

Conversation

@jxom

@jxom jxom commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Moves every wallet flow (dashboard, Slack connect, payment confirm, X link) from the Tempo Wallet dialog to server redirects through Tempo ID, using the backend plugin of accounts@1.0.0-alpha.1. Removes accounts@0.15 and wagmi.

Flow

Before, each link opened a tip.bot page, which opened the Tempo Wallet dialog in the browser, and the browser posted the key authorization or signed transaction back to tip.bot. Now each link opens a start route, which calls backend.start with the access key's limits, sets the __Host-tempo_id session cookie and an intent cookie, and redirects to Tempo ID at once. Tempo ID returns to one callback, GET /api/auth/callback, which reads the intent. The browser never holds a key authorization.

Slack connect

Before

sequenceDiagram
  participant S as Slack
  participant B as Browser
  participant W as Tempo Wallet dialog
  participant T as tip.bot
  S->>B: click /tip connect link
  B->>T: GET /connect/:token (page loads the link)
  B->>B: click Connect
  B->>W: wallet_connect + authorizeAccessKey (tip.bot's public key)
  W-->>B: address, keyAuthorization
  B->>T: POST /api/account/link/:token
  T->>T: verify, store the access key
  T-->>B: connected
Loading

After

sequenceDiagram
  participant S as Slack
  participant T as tip.bot
  participant ID as Tempo ID
  S->>T: click /tip connect link (/api/account/link/:token/start)
  T-->>ID: 302, request a $10/day access key
  ID->>ID: sign in, approve, deposit if below $1
  ID-->>T: 302 /api/auth/callback?code (intent: link)
  T->>T: store the access key, link the member to the account
  T-->>S: 302 /connect/:token?status=connected
Loading
  1. The access key may spend $10 a day of the workspace token, through transfer and transferWithMemo only. Tempo ID's approval page names these limits.
  2. The callback writes Tempo ID's access key onto the link row, then runs the existing link logic.
  3. If another member of the workspace holds the wallet, the callback returns ?status=conflict. Its button posts to /api/account/link/:token/resolve, which links again with the session's access key.

Slack payment confirm

Before

sequenceDiagram
  participant S as Slack
  participant B as Browser
  participant W as Tempo Wallet dialog
  participant T as tip.bot
  participant C as Tempo
  S->>B: click confirm link
  B->>T: GET /confirm/:token (summary, transactionRequest)
  B->>B: click Confirm payment
  B->>W: one-time: eth_signTransaction, reusable: authorizeAccessKey
  W-->>B: signedTransaction or keyAuthorization
  B->>T: POST /api/confirm/:token
  T->>C: submit the payment
  T-->>B: transactionHash
Loading

After

sequenceDiagram
  participant S as Slack
  participant T as tip.bot
  participant ID as Tempo ID
  participant C as Tempo
  S->>T: click confirm link (/api/confirm/:token/start)
  T-->>ID: 302, request the payment's access key
  ID->>ID: sign in, approve
  ID-->>T: 302 /api/auth/callback?code (intent: confirm)
  T->>C: transfer, signed with the access key
  T->>S: post the receipt
  T-->>S: 302 /confirm/:token?status=sent&tx=…&chain=…
Loading
  1. A one-time payment requests an access key for its total, scoped to its recipients, until the link expires, in place of a signed transaction. A reusable confirmation requests the same $10/day access key as a connect.
  2. The callback runs the existing confirm logic, which sends the payment and posts the Slack receipt.
  3. /confirm/$token shows the result: sent with its receipt, an error with Try again, or an expired link. The payment summary and the lost-wallet-session recovery are gone.

X with OAuth

Before

sequenceDiagram
  participant B as Browser
  participant W as Tempo Wallet dialog
  participant T as tip.bot
  participant X as X
  B->>T: POST /api/link/twitter/oauth/challenge
  B->>W: Connect wallet: authorizeAccessKey (challenge's public key)
  W-->>B: address, keyAuthorization
  B->>T: Connect X: POST /api/link/twitter/oauth/start
  T-->>B: authorizationUrl
  B->>X: sign in to X
  X-->>T: 302 /api/link/twitter/oauth/callback
  T-->>B: 302 /link/x?status=connected
Loading

After

sequenceDiagram
  participant B as Browser
  participant T as tip.bot
  participant ID as Tempo ID
  participant X as X
  B->>T: Connect X (/api/link/twitter/oauth/begin)
  T-->>ID: 302, request a $10/day access key
  ID->>ID: sign in, approve
  ID-->>T: 302 /api/auth/callback?code (intent: x_oauth)
  T->>T: store the access key on the challenge
  T-->>X: 302 to X authorize
  X-->>T: 302 /api/link/twitter/oauth/callback
  T-->>B: 302 /link/x?status=connected
Loading

X with a proof tweet

Before

sequenceDiagram
  participant B as Browser
  participant W as Tempo Wallet dialog
  participant T as tip.bot
  participant X as X
  B->>T: POST /api/link/twitter/challenge (username)
  B->>W: authorizeAccessKey (challenge's public key)
  W-->>B: address, keyAuthorization
  B->>T: POST /api/link/twitter/proof
  T-->>B: tweet text
  B->>X: post the proof tweet
  B->>T: poll /api/link/twitter/verify
  T-->>B: connected
Loading

After

sequenceDiagram
  participant B as Browser
  participant T as tip.bot
  participant ID as Tempo ID
  participant X as X
  B->>T: username (/api/link/twitter/proof/begin)
  T-->>ID: 302, request a $10/day access key
  ID->>ID: sign in, approve
  ID-->>T: 302 /api/auth/callback?code (intent: x_proof)
  T->>T: store the access key, prepare the proof
  T-->>B: 302 /link/x?challenge=…&proof=…
  B->>X: post the proof tweet
  B->>T: poll /api/link/twitter/verify
  T-->>B: connected
Loading

Dashboard

Before

sequenceDiagram
  participant B as Browser
  participant W as Tempo Wallet dialog
  participant T as tip.bot
  B->>B: click Dashboard
  B->>W: wallet_connect + auth capability
  W->>T: /api/auth challenge, sign-in with Ethereum
  T->>T: check the nonce (NonceStorage)
  T-->>B: session cookie, /dash
Loading

After

sequenceDiagram
  participant B as Browser
  participant T as tip.bot
  participant ID as Tempo ID
  B->>T: Dashboard (/api/auth/start)
  T-->>ID: 302, sign-in without an access key
  ID->>ID: sign in, approve
  ID-->>T: 302 /api/auth/callback?code (intent: dash)
  T-->>B: 302 /dash
Loading

/dash reads the address from the session, and Sign out posts to /api/auth/logout, which revokes the refresh token.

Changes

  • Sessions live in the TempoIdSessions Durable Object (DurableObject.sessions). Migration tempo_id_sessions_v1 deletes the NonceStorage class of the old wallet sign-in.
  • Tips still sign with the access keys in access_key, so a lapsed Tempo ID session stops no tip.
  • /connect/$token and /confirm/$token show only results. The eth_signTransaction path, transactionRequest, and the confirm page's payment summary are removed.
  • The funding hint names USDC.e on mainnet only.
  • viem → ^2.57.12 and ox → 0.14.59, as accounts v1 requires. QueryClientProvider moves to router.tsx.

Tests

  • The e2e suite starts ghcr.io/tempoxyz/id-dev and a local Tempo node. Specs sign in through Tempo ID's real pages: dashboard sign-in and sign-out, connect and conflict, one-time and reusable confirmations with real payments, X OAuth up to X's authorize page, and the proof tweet page.
  • Workers tests confirm one-time payments with key authorizations in place of signed transactions.
  • Locally: e2e 16/16, unit + workers 352/353 (the failure needs a sqlite3 binary, as on main), vp check and tsc clean.

Before merge

  • Register the first-party app tipbot in Tempo ID with a client secret and https://tip.bot/api/auth/callback. Each preview host needs its own callback.
  • Set TEMPO_ID_CLIENT_SECRET in production and previews, and pass it in the preview deploy workflows. It is a required secret.
  • Give tempoxyz/tip.bot read access to the id-dev package, for the e2e job's GHCR login.
  • Check whether returning users keep their wallet address under Tempo ID.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D3nmWin1mVpioUPdvvsHgw

…n of `accounts` v1

Adds `src/lib/tempoId.ts` and `GET /api/auth/start`, `GET /api/auth/callback`, and
`POST /api/auth/logout`, and reads the dashboard's address from the Tempo ID session. Installs
`accounts@1.0.0-alpha.1` as `tempo-accounts`. Wrangler bindings, the home page button, and tests are
not updated yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3nmWin1mVpioUPdvvsHgw
…irects with `accounts` v1

Replaces `accounts@0.15` and wagmi with `accounts@1.0.0-alpha.1` and its `backend` plugin, with
sessions in the `TempoIdSessions` Durable Object. `GET /api/auth/callback` adopts the session's
access key into the link, the confirmation, or the X challenge, then runs the existing link and
confirm logic. One-time payments authorize a recipient-scoped access key in place of a signed
transaction. Removes the wallet sign-in proxy, `WalletProviders`, and `confirmationWallet`, and
starts `ghcr.io/tempoxyz/id-dev` in the end-to-end suite. The confirm and X link specs are not
updated yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3nmWin1mVpioUPdvvsHgw
… a local Tempo node

Starts a local Tempo node in the end-to-end setup through `test/tempo.ts`, which the workers setup
shares. The confirm spec connects a Tempo Account, funds it, and confirms one-time and reusable
payments through Tempo ID's approval page. The X link spec follows the OAuth redirect to X and the
proof tweet page. CI logs in to GHCR for the pinned `ID_DEV_IMAGE`. Also passes the X OAuth client
to the end-to-end dev server, and puts the dashboard's component before its route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3nmWin1mVpioUPdvvsHgw
@socket-security

socket-security Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedaccounts@​1.0.0-alpha.186100100100100
Updatedviem@​2.55.10 ⏵ 2.57.1697100100 +198 +1100
Updatedox@​0.14.33 ⏵ 0.14.599910099 +197100

View full report

@socket-security

socket-security Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Caution

Review the following alerts detected in dependencies.

According to your organization's Security Policy, you must resolve all "Block" alerts before proceeding. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
Low priority
Recently published: npm accounts published 4 hours ago

Location: Package overview

From: package.json → npm/accounts@1.0.0-alpha.1

ℹ Read more on: This package | This alert | What are recently published artifacts?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should either be allowlisted to allow recently-published versions, or an older version should be used instead.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/accounts@1.0.0-alpha.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Block

View full report

…D sign-in

The Slack messages link to `/api/account/link/:token/start` and `/api/confirm/:token/start`. The
`/connect/$token` and `/confirm/$token` pages show only the result: connected, the conflict to
resolve, sent with its receipt, an error with a retry, or an expired link. Removes their loaders and
the payment summary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3nmWin1mVpioUPdvvsHgw
@jxom jxom changed the title feat: sign in and authorize access keys through Tempo ID with accounts v1 feat: sign in and authorize access keys through Tempo ID with accounts@alpha Nov 4, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants