Skip to content

Optimize tokenRequired middleware performance#467

Merged
dahlia merged 1 commit intofedify-dev:mainfrom
dahlia:token-required-perf
May 5, 2026
Merged

Optimize tokenRequired middleware performance#467
dahlia merged 1 commit intofedify-dev:mainfrom
dahlia:token-required-perf

Conversation

@dahlia
Copy link
Copy Markdown
Member

@dahlia dahlia commented May 5, 2026

Every authenticated API request used to trigger a four-table JOIN: access_tokens joined to account_owners, then accounts, then accounts again for the successor relation, plus applications. Most handlers only need to know whether the token is valid and which scopes it has.

The middleware now does two separate jobs. src/oauth/middleware.ts exports a tokenRequired that reads only from access_tokens, and a new withAccountOwner that fetches account_owners, accounts, and the successor account only when a route needs them. Routes that need account data chain withAccountOwner after scopeRequired, so invalid scopes fail before the account query runs.

The context type is split the same way: Variables contains only the token, and AccountOwnerVariables adds the account owner. That makes accidental accountOwner access harder in handlers that did not include withAccountOwner.

The refactor also exposed a few unrelated bugs:

  • GET /api/v1/apps/verify_credentials now queries the application directly by applicationId instead of relying on the eager-loaded relation.
  • GET /api/v1/tags/:id no longer blocks client-credentials tokens. It now returns following: false, matching Mastodon's "OAuth: Public, or User token" behavior. The follow and unfollow handlers in src/api/v1/tags.ts also had no WHERE clause, so they could update every account owner row.
  • The OIDC userinfo endpoint in src/oauth/endpoints/userinfo.ts now fetches the account owner inline. It keeps returning 401 for client-credentials tokens instead of inheriting the 422 used by withAccountOwner for Mastodon API routes.

Closes #127.

Split the heavy multi-table JOIN in tokenRequired into two separate
queries: a lightweight single-table lookup on access_tokens (always),
and a new withAccountOwner middleware that fetches account_owners +
accounts + successor only when the route actually needs it.

This means requests that fail scope validation never touch the accounts
table at all, and the per-request query plan is significantly simpler.

Changes:
- tokenRequired now issues a single SELECT on access_tokens (no JOINs)
- New withAccountOwner middleware fetches account owner on demand;
  returns 422 if the token has no associated user (client credentials)
- Variables type split into Variables (token only) and
  AccountOwnerVariables (token + accountOwner) for better type safety
- All API routes that need the account owner now chain withAccountOwner
  after scopeRequired, so scope failures short-circuit before the DB hit
- GET /api/v1/apps/verify_credentials fetches the application inline
- GET /api/v1/tags/:id handles client credentials tokens correctly
  (returns following: false) instead of rejecting with 422
- Fixed a pre-existing bug in POST /api/v1/tags/:id/follow and unfollow
  where the UPDATE had no WHERE clause and would have updated every
  account owner row
- OIDC /oauth/userinfo keeps its 401 (not 422) for client credentials
  tokens, consistent with RFC 6750

Closes fedify-dev#127

Assisted-by: Claude Code:claude-sonnet-4-6
Assisted-by: Codex:gpt-5.5
@dahlia dahlia added this to the Hollo 0.9 milestone May 5, 2026
@dahlia dahlia self-assigned this May 5, 2026
@dahlia dahlia added the enhancement New feature or request label May 5, 2026
@dahlia
Copy link
Copy Markdown
Member Author

dahlia commented May 5, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dahlia dahlia merged commit cc7bbb0 into fedify-dev:main May 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve performance of tokenRequired middleware

1 participant