Spioune
Spioune5mo ago

Custom auth

Hi everyone, I am trying to understand how auth works in convex. I want to implement custom oauth and not use clerk or auth0. What I usually do is I have 2 endpoints per providers. For example, /oauth/google that redirects users to the google login page, and another endpoint /oauth/google/callback that get the user profile and insert it into the database. Then I create a custom JWT, redirect the user to https://frontend/?access_token=***, extract the access_token on the frontend (SPA), store it in local storage, then include it in every requests I make to my API. I know I can create endpoints with http actions (for oauth redirect and callback), store users in the database and generare JWT but is there a way to setup the convex javascript client to send my own JWT on every requests? I tried to use client.setAuth() but it says provider not recognized. My goal is to be able to use convex built in ctx.auth in server functions so that I don't have to fetch the user manually at the beginning of every function.
13 Replies
Convex Bot
Convex Bot5mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
sshader
sshader5mo ago
You might want to check out https://labs.convex.dev/auth (either to use directly, or to use as a reference implementation). Auth with Convex works with JWTs -- you generally provide the client (e.g. React client, JS client, but lmk if you're using a different client) with a fetchToken function that fetches a JWT client-side (e.g. reading from local storage, making a call to something like clerk / auth0). And then the Convex backend will validate that this token is valid according to the OIDC spec using your auth.config.ts. As long as your implementation of fetchToken respects the forceRefresh parameter (i.e. it returns a new JWT when forceRefresh is true), the Convex client handles refetching the token and making sure the backend always has an up to date token. If you're seeing errors like "no provider found" or that the token is not valid, I'd check that the token matches up with you auth.config.ts (specifically the iss field should match a domain in your auth.config.ts) -- check out https://docs.convex.dev/auth/debug#step-3-check-that-backend-configuration-matches-frontend-configuration
Convex Auth - Convex Auth
Authentication library for your Convex backend
Debugging Authentication | Convex Developer Hub
You have followed one of our authentication guides but something is not working.
Spioune
SpiouneOP5mo ago
Thank you for your help. I looked at convex auth source code (which is for react only?) and it looks like that's what I am trying to achieve, but with svelte. I am still confused about setAuth and auth.config.js. It looks like setAuth requires an IdToken and not an access token. And it looks like convex backend will try to validate the IdToken based on the provider in the "iss" and will try to reach well-known/jkws.json? Does that mean if I want to use my own token in setAuth() I need to implement my own oauth backend (with the well-known/jwks.json endpoint)?
ballingt
ballingt5mo ago
Yes, sounds like you have the right understanding of this. If it is your goal to implement auth without using Clerk or Auth0, then using Convex Auth directly seems like the way to go. It implements well-known/jkws.json etc. for you, as an OAuth OpenID Connect ID provider. If you don't want to use the Convex Auth library, but you want to mint your own JWTs that can be used with setAuth with Convex, then yes that's exactly right, setAuth requires an identity token. So yes, if you want to use your own token in setAuth you need to implement your own OAuth backend. The Convex Auth library does this for you, so it's a good place to start.
ballingt
ballingt5mo ago
(which is for react only?)
Yeah, I count about 600 liners of React code in https://github.com/get-convex/convex-auth/tree/main/src/react so if you want to do this with Svelte, that's the part you'll need to reimplement.
GitHub
convex-auth/src/react at main · get-convex/convex-auth
Library for built-in auth. Contribute to get-convex/convex-auth development by creating an account on GitHub.
Spioune
SpiouneOP5mo ago
Thanks! I just realized I can still use convex-auth backend part and implement only the svelte front end part.
AmohPrince
AmohPrince3mo ago
Hello @Tom and @sshader . I am doing almost the exact same thing with @Spioune . Here is my context. I have already setup a fully custom Oauth flow with google, fully barebones no library just nextjs and ironsession to save the session info. So to make convex aware of my currently signed in user I am using the below pattern
useEffect(() => {
const fetchToken: AuthTokenFetcher = async (args) => {
console.log("args", args);
const { data } = await axios.get<{ token: string | null }>(
`/api/session/token?force=${args.forceRefreshToken}`
);

console.log("data", data);
return data.token;
};

convex.setAuth(fetchToken, (isAuthenticated) => {
console.log("Auth status changed:", isAuthenticated);
});
}, []);
useEffect(() => {
const fetchToken: AuthTokenFetcher = async (args) => {
console.log("args", args);
const { data } = await axios.get<{ token: string | null }>(
`/api/session/token?force=${args.forceRefreshToken}`
);

console.log("data", data);
return data.token;
};

convex.setAuth(fetchToken, (isAuthenticated) => {
console.log("Auth status changed:", isAuthenticated);
});
}, []);
that almost works. I get a valid token in my own unique ways and return it. but i get the error message Failed to authenticate: "No auth provider found matching the given token", check your server auth config okay. now with my many searches online i think I am supposed to follow the link shared by @sshader that guides setting up with convex auth but in my following it seems convex is kind of tied to auth.js especially the part of getting the Google provider. Bro I cannot stress enough how much I want to avoid that library. I do not want to see it at all in my codebase. How can I avoid the error without having to install AuthJS. Here is my current auth.config.ts
import Google from "@auth/core/providers/google";

// eslint-disable-next-line import/no-anonymous-default-export
export default {
providers: [Google],
};
import Google from "@auth/core/providers/google";

// eslint-disable-next-line import/no-anonymous-default-export
export default {
providers: [Google],
};
ballingt
ballingt3mo ago
The Convex Auth library is built around sharing code with Auth.js. It sounds like you don't want to use the Convex Auth library (npm library @convex-dev/auth), but instead you want to use the built in auth support that is part of Convex (npm library convex) That allows you to use your own JWT if you add the right info to convex/auth.config.ts. See https://docs.convex.dev/auth/advanced/custom-auth.
Spioune
SpiouneOP3mo ago
Hi @AmohPrince I came to the conclusion that no matter how "custom" you want to implement your auth, the only thing you cannot control is how convex backend validates the token you pass to setAuth(). It does this by looking at the "iss" field inside the token (it needs to be a JWT, so your iron session token won't work), looks at your auth.conf.ts to find the matching iss then calls the /.well-known/jwks.json endpoint to get the public keys to verify the token. So if you want to be 100% custom auth, you will need to implement this (see OpenID spec). I didn't go this far and I didn't use convex for a long time so my memory is a bit rusty. But that's what I remember. @Tom it would be nice if we could have our own token validator on the backend and setAuth would then just be a way to attach any session id to the requests. Then for DX, convex could provide an already made function that does the OICD validation like it is done today.
AmohPrince
AmohPrince3mo ago
Thanks @Spioune . I found out a way here https://docs.convex.dev/auth/advanced/custom-auth it worked for me
Custom Auth Integration | Convex Developer Hub
Note: This is an advanced feature! We recommend sticking with the
Pedro Martinez
Hi Everyone! I'm trying to use custom auth with Convex in a React Native app, but so far, no luck. Here's what I have: * I retrieve the token from my third-party SDK. * I’ve added a hook to pass the token to ConvexProviderWithAuth, and I’ve set the Convex client to use verbose: true. * I checked the token on jwt.io, and it includes all the required fields listed in https://docs.convex.dev/auth/debug * I’ve configured auth-config on the backend, and I know it’s working—if I change the domain, I get a "provider not found" error instead. * I also have another working Clerk provider set up for the web version and another app flavor. * When the token is expired, I can see it in the React Native logs (WebSocket authentication error). So the token is being received on backend. The current error i got is: DEBUG 2025-04-24T14:01:24.322Z received ws message with type AuthError DEBUG 2025-04-24T14:01:24.324Z attempting to reauthenticate: Could not verify token claim [v1] At this point i'm stuck, which claim could be missing?
Debugging Authentication | Convex Developer Hub
You have followed one of our authentication guides but something is not working.
Pedro Martinez
My token's aud claim is an array, that could be the issue? i added only one option to the applicationID config, both are urls If i set a wrong applicationID the error changes to attempting to reauthenticate: No auth provider found matching the given token [v1]
erquhart
erquhart2w ago
Yep, multiple audiences aren't supported (source) - I'm not certain whether an array with a single value works, it might. But using a string with a single audience here should definitely fix.

Did you find this page helpful?