StoicWanderer
StoicWanderer14mo ago

How to make authenticated calls to mutations and queries?

Hello people, I am creating a game in next.js and using Convex for it, plust Clerk for website authentication. My question is, tha do i need to check or make authenticated calls for mutations and queries, when for exmaple I want to send the Chat messages, users will write in the Chat functionality, to Convex database? Does the ctx.auth object have other possibilities other than getUserIdentity? Or maybe I'm viewing it from the wrong angle, about how to use authentication in Convex queries and mutaitons. If so, is there an exmaple for this, which could help me wrap my head around it?
9 Replies
Indy
Indy14mo ago
If you set up Clerk correctly ctx.auth.getUserIdentity() should be automatically filled out in queries and mutation functions. https://docs.convex.dev/auth/clerk
Convex Clerk | Convex Developer Hub
Clerk is an authentication platform providing login via
CodingWithJamal
CodingWithJamal14mo ago
In my code i use it like this:
export async function isAuthenticated(auth: Auth) {
const identity = await auth.getUserIdentity();

if (!identity) {
throw new IConvexError({
code: 'Unauthorized',
message: 'No identity found',
});
}

return identity;
}
export async function isAuthenticated(auth: Auth) {
const identity = await auth.getUserIdentity();

if (!identity) {
throw new IConvexError({
code: 'Unauthorized',
message: 'No identity found',
});
}

return identity;
}
and in your mutation or query you can get the auth from ctx.auth or { auth }
handler: async ({ auth}) => { ... }
handler: async ({ auth}) => { ... }
The data in getUserIdentity is already set for you by convex when you pass clerks useAuth hook to the ConvexProviderWithClerk
import { useAuth } from "@clerk/clerk-react";

<ConvexProviderWithClerk useAuth={useAuth}>
{children}
</ConvexProviderWithClerk>
import { useAuth } from "@clerk/clerk-react";

<ConvexProviderWithClerk useAuth={useAuth}>
{children}
</ConvexProviderWithClerk>
CodingWithJamal
CodingWithJamal14mo ago
Final: OpenID Connect Core 1.0 incorporating errata set 1
OpenID Connect Core 1.0 incorporating errata set 1
StoicWanderer
StoicWandererOP14mo ago
@Indy @CodingWithJamal Thank you for the examples
CodingWithJamal
CodingWithJamal14mo ago
no problem
Matt Luo
Matt Luo8mo ago
My app keeps meeting the if (!identity) condition and going down the 'No Identity found' path. What steps can I do to troubleshoot? I will get an error on the front end like: Unhandled Runtime Error Error: [CONVEX Q(userSettings:getUserSettingsByTokenIdentifier)] [Request ID: c162d4695c70ec96] Server Error Uncaught Error: Unauthenticated call to function at handler (../convex/userSettings.ts:107:4) Called by client Does a line like this const identity = await ctx.auth.getUserIdentity(); only work in Convex mutations and not queries? Looking through each of the Next.js apps in the Convex templates, I dont see this line: const identity = await ctx.auth.getUserIdentity(); in any query So this code in /convex/userSettings.ts will throw that unhandled runtime error: export const getUserSettingsByTokenIdentifier = query({ handler: async (ctx) => { // Get the user identity, which includes the tokenIdentifier const identity = await ctx.auth.getUserIdentity(); // If there's no identity found, invalidate the request (unauthenticated) if (!identity) { throw new Error('Unauthenticated call to function'); } const user = await ctx.db .query('users') .withIndex('by_token', (q) => q.eq('tokenIdentifier', identity.tokenIdentifier), ) .unique(); if (!user) { throw new Error('User not found in users'); } // Then, query the userSettings table using the obtained user._id const userSettings = await ctx.db .query('userSettings') .filter((q) => q.eq(q.field('userId'), user._id)) .first(); // If no settings are found for the user, throw an error if (!userSettings) { throw new Error('Settings not found for this user'); } return userSettings; }, }); Source of the error where the query is called: src/app/(try-convex)/two-part-query-function/page.tsx (29:5) @ api 27 | 28 | const selectUserSettingsData = useQuery(
29 | api.userSettings.getUserSettingsByTokenIdentifier,
| ^ 30 | ); 31 | The spirit of what I am trying to do is use one query function, getUserSettingsByTokenIdentifier, to 1) get the tokenIdentifier from Clerk 2) select from the users table 3) select from the userSettings table. The exception is happening because the identity is not found in the query function.
Matt Luo
Matt Luo8mo ago
Following https://docs.convex.dev/auth/debug Seems like I am not getting an Authenticate message at all
No description
lee
lee8mo ago
is the useQuery inside a component that is nested inside a <Authenticated> component?
Matt Luo
Matt Luo8mo ago
Ah, no it is not. my app is not using <Authenticated> anywhere. I thought that since my page.tsx is required by Clerk middleware.ts to be authenticated, then <Authenticated> was not necessary @lee - I think there is some coding issue that VS Code is not warning me about. If I simplify things and just try to get the userIdentity (and not the user settings) from my Next.js page.tsx: const authUserIdentity = useQuery(api.userSettings.queryAuthUserIdentity, {}); I am able to successfully see the type: "Authenticate" message in my console log, as well as render the userIdentity on my front end. Here is the relevant code from my /convex/userSettings.ts:
export const getAuthUserIdentity = async (ctx: { auth: Auth }) => {
return await ctx.auth.getUserIdentity();
};

export const queryAuthUserIdentity = query({
args: {},
handler: async (ctx) => {
const userId = await getAuthUserIdentity(ctx);
if (!userId) return null;
return userId;
},
});
export const getAuthUserIdentity = async (ctx: { auth: Auth }) => {
return await ctx.auth.getUserIdentity();
};

export const queryAuthUserIdentity = query({
args: {},
handler: async (ctx) => {
const userId = await getAuthUserIdentity(ctx);
if (!userId) return null;
return userId;
},
});
But when I try to make my page.tsx call my Convex query function, getUserSettingsByTokenIdentifier, that does multiple steps, 1) get the userIdentity 2) select from users 3) select from userSettings This is when I get in this situation where Chrome is not even showing an Authenticate message in my console log.

Did you find this page helpful?