Security

Keep your authentication secure

It will likely be paramount to your app that your authentication stays secure. Secure means that malicious actors cannot impersonate other users, to retrieve their data or act on their behalf.

The authentication methods your choose will impact security, see the Configuration page.

This page focuses on the core mechanisms Convex Auth uses, and how to make sure they stay secure.

Client secrets storage

Convex Auth lets you authenticate your React app, which talks to your Convex backend over a WebSocket. Convex auth makes client credentials available to your JavaScript because:

  1. For web-apps, your Convex backend is a third-party server - it does not host your web app, and so any cookie would be considered third-party and blocked by some browsers such as Safari.
  2. Browsers do not support server-only cookies for WebSocket connections.
  3. React Native does not have good support for cookies - they don't work in Expo Go for example.

Convex Auth makes two values available to the client JavaScript:

  1. A refresh token, used to maintain a session (including across page loads)
  2. A JWT access token, which is sent over the WebSocket connection back to the backend

To allow immediate authentication across page loads, both are stored in localStorage (opens in a new tab) by default, but you can choose a different storage mechanism via the storage prop.

The refresh token can be used only once to get a new access token. And using an "old" refresh token will invalidate the whole session (this is called refresh token reuse detection).

Since these tokens are accessible via JavaScript, to keep your authentication secure you should take every precaution to avoid XSS (opens in a new tab) and similar vulnerabilities.

Preventing XSS

Since your app uses React, you are already protected from typical XSS attacks, as long as you don't circumvent (opens in a new tab) React's protections.

You should also carefully review and frequently update any dependencies to prevent supply-chain attacks (opens in a new tab).

Make sure to further protect more sensitive actions the user can take by requiring a recent sign-in.

Handling XSS vulnerability

If you discover an XSS vulnerability in your app, and you're relying on Convex Auth, you should take the following steps, in order:

Fix the XSS vulnerability

This depends on the vulnerability, but it's usually fixable on the server, even in cases where the client is to blame for improper sanitization.

Delete all existing sessions

You can do this by clearing the authSessions table in the Convex dashboard.

This will immediately prevent any authenticated clients from getting new access tokens, and will force all users to sign in again.

Rotate your private and public key

You can run:

npx @convex-dev/auth --prod

and answer Yes to reset the keys on your production deployment, or do this manually.

This will immediately invalidate all existing access tokens, although existing WebSocket connections will stay authenticated until the token expires (1 hour by default), unless your code validates the session ID.

Next.js

If your app uses @convex-dev/auth/nextjs, it will also use server-only cookies to store the session ID and access token, to make them accessible by your Next.js server on an initial page load.

Protecting refresh tokens

With @convex-dev/auth/nextjs, only the access token is made available to client-side JavaScript. This makes refresh tokens even more secure, since an attacker cannot steal a refresh token via an XSS vulnerability.

Preventing CSRF

Since cookies are used, the library takes care of protecting your app against CSRF (opens in a new tab), as long as you follow the rules mentioned here.