New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thoughts on protecting some methods behind authentication and permissions #1
Comments
Hey @TheBestMoshe I like your suggestion very much. How do you feel about an option that let's you pass a custom middleware. This middleware will be applied to all routers: export const postsRouter = createRouter()
.middleware(async ({ ctx, next }) => {
if (!ctx.user?.isAdmin) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next();
})
.mutation("findUniquePost", {
input: PostFindUniqueSchema,
async resolve({ ctx, input }) {
const findUniquePost = await ctx.prisma.post.findUnique(input);
return findUniquePost;
},
}) So that way, you can have as many custom cases you need, all in one place. Would that solve your problem? Please let me know if you have any other implementation ideas in mind. |
How about a middleware per router, not a global one? |
The directive way inside the Prisma schema could have worked if we're spelling out all possible procedures in the Prisma schema itself, but unfortunately, we only spell models and enums. It was only possible in GraphQL schemas. |
I guess the most sane thing to do here is a middleware that handles auth inside of it based on proc name. Very soon, I'm looking to build a separate middleware library that makes proc auth a breeze. |
@omar-dulaimi I agree that a middleware might be the best approach. Especially if the Prisma tRPC Generator can generate helper functions that can include the typescript definitions of the possible inputs and outputs. I think a middleware approach would be more flexible than declaring it in the Prisma file. This would enable arbitrary rules that do not need to be built into the library.
This sounds like a great approach! |
@TheBestMoshe Thank you for the feedback. I have implemented the middleware solution and it's out now in I appreciate it. |
Hello @TheBestMoshe Announcing tRPC Shield take this example: const permissions = shield({
query: {
fruits: and(isAuthenticated, or(isAdmin, isEditor)),
customers: and(isAuthenticated, isAdmin),
},
mutation: {
addFruitToBasket: isAuthenticated,
},
}) You can define rules as you like, then mix and match then to get exactly what you need with logical operators. To make things even smoother for tRPC users who also use Prisma, I built a new generator that takes care of emitting the right shield for your Prisma schema: import { shield, allow } from 'trpc-shield';
export const permissions = shield({
query: {
aggregatePost: allow,
aggregateUser: allow,
findFirstPost: allow,
findFirstUser: allow,
findManyPost: allow,
findManyUser: allow,
findUniquePost: allow,
findUniqueUser: allow,
groupByPost: allow,
groupByUser: allow,
},
mutation: {
createOnePost: allow,
createOneUser: allow,
deleteManyPost: allow,
deleteManyUser: allow,
deleteOnePost: allow,
deleteOneUser: allow,
updateManyPost: allow,
updateManyUser: allow,
updateOnePost: allow,
updateOneUser: allow,
upsertOnePost: allow,
upsertOneUser: allow,
},
}); You can fined them here: |
@omar-dulaimi can you please document this feature? I'd like to know how I can pass a custom middleware or configure the permissions. thanks :) |
Hey @MartinMuzatko To pass a custom middleware, you only need to pass the generator trpc {
provider = "prisma-trpc-generator"
withMiddleware = true
} Same thing if you want to get a shield generated: generator trpc {
provider = "prisma-trpc-generator"
withShield = true
} You could also generate both of them if you add both flags above. To learn more about tRPC Shield and how to configure it's permissions, you should go here: https://github.com/omar-dulaimi/trpc-shield It explains all possible options in that project README :) |
I am not sure I understand correctly. The point of Shield and custom middleware is that I can customize them. If they are generated, how can I update them, without having the generator overwriting them again? Surely, if I just test this out, I'll see how things work out. But that is something I would like to know before I even install the module to my pc, when looking for new things that fit into my stack :) I'll report back once I know more. |
The purpose of all Prisma generators is to always be in-sync with the Prisma schema and client. So, yeah it will overwrite every time a generate happens. Best thing you can do is imagine them as snippets generators. You could use them as is or modify them to your liking, in another directory where it will be source control tracked. The middleware lies inside the helpers directory, in the |
FWIW I'm having this same issue. Feels like this could be resolved more generically by allowing the caller to configure a their own custom I need this functionality and can configure it in a fork I'm maintaining. Happy to PR the change into the upstream if there's appetite for it. |
Problem
Currently, this generator can't be used whenever there needs to be permission per procedure. For example, only some users are supposed to have access to a procedure. Or a procedure requires the user to contain a specific scope in their JWT.
Suggested solution
Add a way to pass information into the generator (maybe directives in the Prisma file?)
Alternatives
Manually write all tRPC procedures by hand.
The text was updated successfully, but these errors were encountered: