much 2 yearn
much 2 yearn12mo ago

Best practice to get userId from from user user in function

in the next/expo monorepo they use getting the userId from the userIdentity, but unsure if this is best practice in case this value will change among auth providers and also because it default to type string and not
Id<"users">
Id<"users">
. Is there a way to get userId from the auth flow for your functions or is the best way to pass the userId as an argument from the frontend?
export const getUserId = async (ctx: { auth: Auth }) => {
return (await ctx.auth.getUserIdentity())?.subject;
};

// Get all notes for a specific user
export const getNotes = query({
args: {},
handler: async (ctx) => {
const userId = await getUserId(ctx);
if (!userId) return null;

const notes = await ctx.db
.query('notes')
.filter((q) => q.eq(q.field('userId'), userId))
.collect();

return notes;
},
});
export const getUserId = async (ctx: { auth: Auth }) => {
return (await ctx.auth.getUserIdentity())?.subject;
};

// Get all notes for a specific user
export const getNotes = query({
args: {},
handler: async (ctx) => {
const userId = await getUserId(ctx);
if (!userId) return null;

const notes = await ctx.db
.query('notes')
.filter((q) => q.eq(q.field('userId'), userId))
.collect();

return notes;
},
});
vs
export const getNotes = query({
args: {
userId: Id<"users">
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
throw new Error("Unauthenticated call to mutation");
}

const notes = await ctx.db
.query('notes')
.filter((q) => q.eq(q.field('userId'), args.userId))
.collect();

return notes;
},
});
export const getNotes = query({
args: {
userId: Id<"users">
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
throw new Error("Unauthenticated call to mutation");
}

const notes = await ctx.db
.query('notes')
.filter((q) => q.eq(q.field('userId'), args.userId))
.collect();

return notes;
},
});
5 Replies
lee
lee12mo ago
The latter code looks like it has a security hole. User "tom" can be authenticated, but pass up the userId for user "lee". So any user can fetch the notes for any other user
lee
lee12mo ago
I would go with the former, always getting user id from ctx.auth. If you want to reuse code more, you can use a customQuery to get the auth before every function call. https://www.npmjs.com/package/convex-helpers
npm
convex-helpers
A collection of useful code to complement the official convex package.. Latest version: 0.1.25, last published: 6 days ago. Start using convex-helpers in your project by running npm i convex-helpers. There are no other projects in the npm registry using convex-helpers.
lee
lee12mo ago
Oh and if you want to convert user identity to Id<"users">, you would use db.query("users"). https://docs.convex.dev/auth/database-auth
Storing Users in the Convex Database | Convex Developer Hub
You might want to have a centralized place that stores information about the
much 2 yearn
much 2 yearnOP12mo ago
but will
ctx.auth.getUserIdentity()?.subject
ctx.auth.getUserIdentity()?.subject
always return the userId ? So the flow would be : get userId from the auth ( "subject") , query users table with that id (to convert to
Id<"users">
Id<"users">
, then mutate with the returned
user._id
user._id
? thanks for always helping much appreciated @lee
lee
lee12mo ago
no, getUserIdentity().subject is unrelated to userId. You can fetch one from the other. https://docs.convex.dev/auth/database-auth#reading-from-users-table
Storing Users in the Convex Database | Convex Developer Hub
You might want to have a centralized place that stores information about the

Did you find this page helpful?