Skip to main content

Security Model

Understand the trust boundaries and application responsibilities around Better Convex Nuxt.

Better Convex Nuxt transports identity; it does not replace application authorization. Every protected Convex function must verify the caller and enforce access to the requested resource.

Trust boundaries

BoundaryResponsibility
Nuxt UIDisplay state and capabilities; never final authorization
Nuxt serverRequest-scoped rendering, server routes, and the bounded same-origin auth proxy
Better AuthSession lifecycle and authentication ceremonies
Convex token exchangeConvert the validated session into a Convex identity
Convex functionsCanonical authorization, tenant isolation, validation, and bounded data access

Route middleware improves navigation UX. Hiding a button improves UX. Neither protects data.

convex/projects.ts
export const remove = mutation({
  args: { projectId: v.id('projects') },
  handler: async (ctx, { projectId }) => {
    const identity = await ctx.auth.getUserIdentity()
    if (!identity) throw new ConvexError({ code: 'UNAUTHENTICATED' })

    const project = await ctx.db.get(projectId)
    if (!project || project.ownerId !== identity.subject) {
      throw new ConvexError({ code: 'FORBIDDEN' })
    }

    await ctx.db.delete(projectId)
  },
})

Auth proxy contract

The module exposes one /api/auth proxy. Human, session, consent, administration, authorize, revoke, and plugin routes remain same-origin. It accepts only the supported Better Auth cookie namespace, GET and POST requests, bounded bodies, and a validated upstream origin. It does not follow upstream redirects with credentials attached.

The narrow browser OAuth exception is the exact public-client form token route: cross-origin POST /api/auth/oauth2/token and its exact OPTIONS preflight, without a query, Cookie, Authorization, proxy authorization, DPoP, or credentialed CORS. Its form body is independently bounded, upstream CORS headers cannot widen the response, and a token response that tries to set a cookie is rejected. The public authorization-server and protected-resource metadata documents use wildcard non-credentialed CORS because they contain no secret or user state.

Do not widen its cookie allowlist, add caller-controlled forwarding headers, or introduce a second token-exchange path. If a Better Auth plugin requires cookies outside the supported namespace, it is not compatible with this boundary.

Browser risk

The browser receives a bearer credential so Convex subscriptions can authenticate. An XSS flaw or compromised same-origin script can act as the user and copy that credential until it expires. Use safe Vue rendering, a restrictive Content Security Policy, limited third-party scripts, and proportionate token lifetimes. High-risk operations should revalidate current canonical state in Convex.

Operator responsibilities

You own TLS termination, host validation, secret storage, OAuth provider configuration, recovery delivery, CSP, log access, dependency updates, authorization rules, backups, and incident response. Consult the repository security policy for the current supported boundary and known residual risks.

For a suspected Better Auth secret, proxy signing secret, session, OAuth client, consent/token, signing-key, or package compromise, follow the policy's operator runbooks. They distinguish repository checks from the secret-manager, cloud, npm, and human actions an operator must actually perform.

Report suspected vulnerabilities through the private channel described in that policy, not a public issue.