Drakenhielm
Drakenhielm10mo ago

Verify JWT token signed by Convex

I'm currently in the process of developing my own authentication system. Users log in using an HTTP action, receiving both an HTTP-only session and a short-lived JWT. This JWT is generated through a node runtime action employing jsonwebtoken. However, I've encountered an issue: when it comes to queries and mutations, jsonwebtoken does not work as it requires node, and I'm unable to invoke a node action for JWT verification. I'm considering two possible solutions: 1. Creating a REST API adhering to OpenID standards, allowing Convex to call itself by the built-in functionality for Auth providers. Not sure if calling it self is possible. 2. Exploring the possibility of verifying the JWT using the available crypto web API. Any insights or suggestions on the best approach to resolve this issue would be greatly appreciated!
4 Replies
erquhart
erquhart10mo ago
Actions (but not http actions) can use node, and can call and await the results of queries and mutations. Define the auth action in the node runtime to both parse the token and run any auth related queries/mutations. You can then call that action from the http action.
Michal Srb
Michal Srb10mo ago
1. Works, I have implemented this:
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 (ctx) => {
return new Response(
JSON.stringify({
keys: [
{ use: "sig", ...(await ctx.runAction(internal.node.publicJWK)) },
],
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
}),
});
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 (ctx) => {
return new Response(
JSON.stringify({
keys: [
{ use: "sig", ...(await ctx.runAction(internal.node.publicJWK)) },
],
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
}),
});
@lee where are we on supporting verify in queries/mutations?
lee
lee10mo ago
depends on the crypto algorithm. RSASSA-PKCS1-v1_5 should work with importKey and verify (and sign) in queries/mutations/actions
lee
lee10mo ago
so option (2) would probably work, if you use a library like https://www.npmjs.com/package/jose instead of jsonwebtoken
npm
jose
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes. Latest version: 5.2.3, last published: 12 days ago. Start using jose in your project by running npm i jose. There are 1438 other projects in the npm registry using jose.

Did you find this page helpful?