#how do I implement something like ACL? E.g. prevent updating a row that a user doesn't own
4 messages · Page 1 of 1 (latest)
Hi @wraith tulip. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
In Convex, you can implement something similar to Access Control Lists (ACLs) by using row-level security and authorization checks in your code. This allows you to control which users can perform certain actions, such as updating a row that they don't own.
Here's a simple example of how you can implement this. In this example, we're checking that the authenticated user is the one that "owns" the mutated document before allowing them to delete it:
export const deleteSomething = mutation(
args: { id: v.id("somethings") },
handler: async (ctx, { id }) => {
// getCurrentUser uses `ctx.auth.getUserIdentity()`
const user = await getCurrentUser(ctx);
const something = ctx.db.get(id);
if (user === null || user._id !== something.ownerId) {
throw new Error("Unauthenticated");
}
await ctx.db.delete(id);
},
});
(Source: Discord support thread (https://discord.com/channels/1019350475847499849/1237357470926508043))
You can also use middleware functions to wrap queries and mutations. These functions intercept each row that would be returned from db.get or db.query and filter out rows based on your read rules. They also intercept each row that would be modified by db.patch, db.replace, or db.delete and confirm that the write is allowed by modify rules, and db.insert with the insert rules.
// Example of middleware function
export default likePost = mutation(async ({db, auth}, {postId}) => {
const post = await db.get(postId);
if (!await connectedInGraph(db, await auth.getUserIdentity(), post.author)) {
throw new Error("you can't like that");
}
await db.patch(postId, {likes: post.likes + 1});
});
(Source: Row Level Security: Wrappers as "Middleware" (https://stack.convex.dev/row-level-security#authorization-via-row-level-security))