Skip to content

feat(agent-auth): approvalMethodHandlers for the Server-Defined Approval Profile (§10.10.3) - #38

Open
envisean wants to merge 1 commit into
better-auth:mainfrom
envisean:feat/server-defined-approval-method-handlers
Open

envisean wants to merge 1 commit into
better-auth:mainfrom
envisean:feat/server-defined-approval-method-handlers

Conversation

@envisean

Copy link
Copy Markdown

Summary

§7.4 notes that custom approval methods are "defined, if at all, by extension profiles such as the Server-Defined Approval Profile (§10.10.3)". approvalMethods/resolveApprovalMethod already let a server name and select a custom method, but buildApprovalInfo had no way to actually build one — any resolved method other than "ciba" fell through to the device_authorization branch unconditionally, silently mislabeling the stored ApprovalRequest.

This adds approvalMethodHandlers: a registry of method name → handler on AgentAuthOptions, consulted in buildApprovalInfo before the built-in branches. A resolved method with a matching handler is built by that handler and becomes the approval object in the API response.

  • Additive only — ciba/device_authorization behavior is unchanged, and any resolved method without a registered handler still falls back to device_authorization exactly as before.
  • Per §7's approval-object schema, method/expires_in/interval are required on every method's response, including server-defined ones — noted in the JSDoc as the handler's responsibility. Left the type itself as Record<string, unknown> rather than enforcing this, matching how the two built-in methods are already handled elsewhere in this file (plain object literals, no shared enforced base type).
  • Widens ApprovalRequest.method past its two-value literal union (string & {}) to keep autocomplete for the two built-ins while allowing registered custom names — the underlying column was always a plain string, so this is a type-only change.

Note for maintainers

While researching this against the actual spec (not just this file's existing comments), I noticed the pre-existing §9/§9.5 citations on approvalMethods/resolveApprovalMethod in this same file appear to predate a renumbering — the current v1.0-draft has Approval Methods at §7, with the extension profile at §10.10.3, not §9. §2.4 (lifetime clocks) checks out correctly against the current draft, so this doesn't look like a wholesale renumbering, just this pocket of citations. Didn't touch those pre-existing lines since I didn't introduce them and it's a separate changeset — flagging in case it's worth its own pass.

Test plan

  • Added packages/agent-auth/src/__tests__/server-defined-approval-methods.test.ts: a registered handler wins over the built-ins, device_authorization is unaffected when no handler is registered, a resolved method with no matching handler still falls back to device_authorization, and the same behavior holds through request-capability on an already-active agent, not just at registration.
  • Full existing suite: 260/260 passing (256 pre-existing + 4 new), zero regressions
  • tsc --noEmit clean
  • tsup build clean (ESM + DTS)
  • oxfmt --check clean

…methods

§7.4 notes that custom approval methods "are defined, if at all, by
extension profiles such as the Server-Defined Approval Profile
(§10.10.3)". approvalMethods/resolveApprovalMethod already let a
server name and select a custom method, but buildApprovalInfo had no
way to actually build one -- any resolved method other than "ciba"
fell through to the device_authorization branch unconditionally,
silently mislabeling the stored ApprovalRequest.

Adds approvalMethodHandlers: a registry of method name -> handler on
AgentAuthOptions, consulted in buildApprovalInfo before the built-in
branches. A resolved method with a matching handler is built by that
handler and becomes the approval object in the API response; behavior
for ciba/device_authorization and for any method without a registered
handler is unchanged. Per §7's approval-object schema, method,
expires_in, and interval are required on every method's response,
including server-defined ones -- the handler is responsible for
including them; the type itself stays Record<string, unknown> rather
than enforcing this, matching how the two built-in methods are already
handled elsewhere in this file (plain object literals, no shared
enforced base type).

Widens ApprovalRequest.method past its two-value literal union
(string & {}) to keep autocomplete for the two built-ins while
allowing registered custom names -- the underlying column was always
a plain string, this is a type-only change.

Adds packages/agent-auth/src/__tests__/server-defined-approval-methods.test.ts:
a registered handler wins over the built-ins, device_authorization is
unaffected when no handler is registered, a resolved method with no
matching handler still falls back to device_authorization, and the
same behavior holds through request-capability on an already-active
agent, not just at registration.

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.

1 participant