#Can i setup manual `Auth in Functions`?
1 messages · Page 1 of 1 (latest)
Hi @native prairie. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Yes, you can set up manual authentication for your Convex functions when using your own auth flow with next-auth. There are a few approaches you can take:
Using JWT with Convex's built-in auth system
The most integrated approach is to configure Convex to validate JWTs issued by your Next.js server:
-
Generate a public/private key pair using the
joselibrary:import { exportJWK, exportPKCS8, generateKeyPair } from "jose"; const keys = await generateKeyPair("RS256"); const privateKey = await exportPKCS8(keys.privateKey); const publicKey = await exportJWK(keys.publicKey); const jwks = JSON.stringify({ keys: [{ use: "sig", ...publicKey }] }); -
Set up your Convex
auth.config.tsto recognize your domain:export default { providers: [ { domain: process.env.CONVEX_SITE_URL, applicationID: "convex", }, ], }; -
Expose the JWKS endpoint in your Convex
http.ts:http.route({ path: "/.well-known/jwks.json", method: "GET", handler: httpAction(async () => { return new Response(process.env.JWKS, { status: 200, headers: { "Content-Type": "application/json", }, }); }), }); -
Create a token fetcher function for your client:
const fetchToken = async ({ forceRefreshToken }) => { // Get token from your next-auth session const { data } = await axios.get(`/api/session/token?force=${forceRefreshToken}`); return data.token; }; convex.setAuth(fetchToken);
This approach allows you to use ctx.auth.getUserIdentity() in your Convex functions.
Stack: Convex with Auth.js provides more details on this approach.
Alternative: API Key Authentication
If you prefer a simpler approach without JWT validation, you can use a shared secret:
-
Generate a secret and store it as an environment variable in both Convex and your Next.js app.
-
Pass this secret with your function calls:
const result = await fetchMutation(api.myFunction.doSomething, { param1: value1 }, { apiKey: process.env.SHARED_SECRET } ); -
In your Convex functions, validate the secret:
export const doSomething = mutation({ args: { /* your args */ }, handler: async (ctx, args) => { // Check if the API key matches if (ctx.auth.apiKey !== process.env.SHARED_SECRET) { throw new Error("Unauthorized"); } // Continue with authorized function } });
This approach is mentioned by a Convex support staff in one of the Discord threads as a viable alternative when you don't need the full JWT validation flow.
Choose the approach that best fits your security requirements and implementation preferences.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@native prairie Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@orchid adder i wanna know more about using JWT with convex's built-in auth system ... can you share me docs
Let me check the knowledge base for you again. One moment! :books:
I'd be happy to share more information about using JWT with Convex's built-in auth system. Here are the relevant documentation resources:
Custom Auth with JWT
For implementing custom authentication with JWT in Convex, you can follow the approach outlined in the custom auth documentation:
This documentation explains how to configure Convex to validate JWTs issued by your server.
NextAuth Integration Example
If you're specifically using NextAuth, there's a detailed guide on Stack Convex that walks through the entire process:
Convex Adapter for Auth.js Setup Guide
This guide covers:
- Generating key pairs
- Exposing the public key through Convex HTTP endpoints
- Configuring auth.config.ts
- Issuing JWTs from NextAuth
JWT Implementation Steps
The implementation involves these key steps:
- Generate a public/private key pair using the
joselibrary - Configure your Convex backend with the public key
- Set up the necessary OIDC endpoints in your Convex HTTP router
- Issue JWTs from your NextAuth session callback:
async session({ session }) {
const privateKey = await importPKCS8(
process.env.CONVEX_AUTH_PRIVATE_KEY!,
"RS256",
);
const convexToken = await new SignJWT({
sub: session.userId,
})
.setProtectedHeader({ alg: "RS256" })
.setIssuedAt()
.setIssuer(CONVEX_SITE_URL)
.setAudience("convex")
.setExpirationTime("1h")
.sign(privateKey);
return { ...session, convexToken };
}
- Provide the JWT to the Convex client:
function useAuth() {
const { data: session, update } = useSession();
const convexToken = convexTokenFromSession(session);
return useMemo(
() => ({
isLoading: false,
isAuthenticated: session !== null,
fetchAccessToken: async ({
forceRefreshToken,
}) => {
if (forceRefreshToken) {
const session = await update();
return convexTokenFromSession(session);
}
return convexToken;
},
}),
[JSON.stringify(session?.user)],
);
}
Server-Side Authentication
For server-side authentication in Next.js, you can use the convexAuthNextjsToken function:
Server-side authentication in Next.js
This allows you to make authenticated requests to Convex during server rendering:
import { convexAuthNextjsToken } from "@convex-dev/auth/nextjs/server";
import { preloadQuery } from "convex/nextjs";
import { api } from "@/convex/_generated/api";
export async function TasksWrapper() {
const preloadedTasks = await preloadQuery(
api.tasks.list,
{ list: "default" },
{ token: await convexAuthNextjsToken() },
);
return <Tasks preloadedTasks={preloadedTasks} />;
}
These resources should provide you with comprehensive guidance on implementing JWT authentication with Convex's built-in auth system.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@native prairie Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@orchid adder can i use without adapter?
Let me check the knowledge base for you again. One moment! :books:
Yes, you can use JWT authentication with Convex without using the NextAuth adapter. Based on the knowledge sources, there are several approaches to implement custom authentication without relying on the adapter.
Custom JWT Authentication
You can implement your own JWT authentication flow by:
- Setting up your own JWT generation and validation:
export default {
providers: [
{
domain: process.env.CONVEX_SITE_URL,
applicationID: "convex",
},
],
};
- Exposing the necessary JWKS endpoints in your Convex HTTP router:
http.route({
path: "/.well-known/openid-configuration",
method: "GET",
handler: httpAction(async () => {
return new Response(
JSON.stringify({
issuer: process.env.CONVEX_SITE_URL,
jwks_uri: process.env.CONVEX_SITE_URL + "/.well-known/jwks.json",
authorization_endpoint: process.env.CONVEX_SITE_URL + "/oauth/authorize",
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
},
);
}),
});
http.route({
path: "/.well-known/jwks.json",
method: "GET",
handler: httpAction(async () => {
return new Response(process.env.JWKS, {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}),
});
- Creating a custom
useAuthhook to provide tokens to the Convex client:
function useAuth() {
const { data: session, update } = useSession();
const fetchAccessToken = async ({ forceRefreshToken }) => {
if (forceRefreshToken) {
// Get a fresh token
const newSession = await update();
return newSession?.convexToken || null;
}
return session?.convexToken || null;
};
return {
isLoading: false,
isAuthenticated: session !== null,
fetchAccessToken,
};
}
- Using the custom auth hook with
ConvexProviderWithAuth:
<ConvexProviderWithAuth client={convex} useAuth={useAuth}>
{children}
</ConvexProviderWithAuth>
This approach allows you to generate and validate JWTs without using the Convex adapter for NextAuth, while still being able to use ctx.auth.getUserIdentity() in your Convex functions.
As mentioned in one of the Discord threads, you'll need to ensure your JWT has the proper format and fields that Convex expects, particularly the sub field which should identify your user.
Stack: Convex Adapter for Auth.js Setup Guide provides more details on the JWT requirements and implementation.