Skip to main content
Convex supports custom auth providers via its custom auth feature. Ave works as a drop-in OIDC provider. This guide explains exactly what to configure, which token to pass, and what Convex does with it.

Which token to use

Always pass id_token to Convex. Never pass access_token_jwt. This is the most common mistake when integrating Ave with Convex.
Ave returns two JWTs. They look similar but serve different purposes and have different audiences: Convex validates the aud claim against the applicationID you configure. If you use access_token_jwt, Convex will reject it because its audience is https://aveid.net, not your client ID.

Auth config

Add Ave as a custom provider in convex/auth.config.ts:
domain maps to the iss (issuer) claim in the token. Ave’s issuer is https://aveid.net. Convex fetches {domain}/.well-known/openid-configuration to discover the JWKS endpoint automatically.

What Convex validates

When you call convex.setAuth(idToken) or equivalent, Convex:
  1. Fetches https://aveid.net/.well-known/openid-configuration
  2. Gets the JWKS URL from the discovery document
  3. Downloads and caches signing keys
  4. Verifies the JWT signature (RS256)
  5. Checks iss === "https://aveid.net"
  6. Checks aud === "your_client_id" (the applicationID you configured)
  7. Checks exp > now
If all checks pass, Convex considers the user authenticated and the identity is available as ctx.auth.getUserIdentity().

What claims Convex exposes

After a successful auth check, ctx.auth.getUserIdentity() returns:
The subject is the Ave identity UUID — this is the value you should use as your primary user identifier in Convex.
The sub in the id_token is the identity UUID, not a permanent user UUID. A single Ave user can have multiple identities. If you need a stable cross-identity identifier, request the user_id scope — but note that user_id is in access_token_jwt (the uid claim), not in id_token. For most apps, the identity UUID is the right identifier.

Full implementation

1

Configure auth.config.ts

Store your client ID in an environment variable. Do not hardcode it.
2

Complete the Ave OAuth flow

Follow the OAuth authorization code flow to get tokens. You need the openid scope at minimum — without it, Ave does not return an id_token.
3

Pass id_token to Convex

In a React app, use ConvexProviderWithAuth or the useAuth hook from your auth state to keep the token fresh.
4

Use the identity in mutations and queries

5

Handle token refresh (recommended: Ave Session)

id_token expires (check exp claim). Do not pass a static tokens.id_token to setAuth — Convex validates exp on every request. Prefer Ave Session (AveSession + wireAveSessionToConvex) so refresh is single-flight, persisted, and runs before expiry.Manual refresh (if you are not using AveSession yet):
Default token lifetime is often about one hour (expires_in). Quick Ave has no refresh token — upgrade to a registered app with offline_access. See also Sessions still flaky below.

Sessions still flaky

If users drop out after ~one hour, or behavior feels random even with offline_access:

Complete id_token payload reference

For your reference, here is the full id_token payload shape:
Profile claims are only present when the corresponding scope was granted.

Troubleshooting

You are passing access_token_jwt instead of id_token. The access_token_jwt has aud: "https://aveid.net" — Convex expects aud === your_client_id. Always use id_token.
You did not include openid in the scope parameter of the authorization request. id_token is only issued when the openid scope is granted. Add openid to your scope list.
Verify that domain in auth.config.ts is exactly https://aveid.net. The iss claim in Ave tokens is https://aveid.net. If you have set a custom issuer via the OIDC_ISSUER environment variable in your Ave server, use that value instead.
The token may have expired, or convex.setAuth was not called before the query/mutation ran. Make sure your auth state provider calls convex.setAuth before any authenticated Convex calls.
Server clocks must be reasonably in sync. Convex allows a small tolerance. If you see exp validation failures on otherwise valid tokens, check that your backend server time is accurate.
Last modified on April 19, 2026