Custom directive: requireSameUser

Hey there,
I have a User model in my database where the schema looks something like this (only included some properties):

model User {
  id                    String           @id @default(uuid())
  createdAt             DateTime         @default(now())
  email                 String           @unique
  togglKey              String?          @unique

In my SDL the user is queryable and the users.sdl.ts looks something like this:

  type User {
    id: String!
    createdAt: DateTime!
    email: String!
    togglKey: String 

  type Query {
    user(id: String!): User @requireAuth

So far so good. The to query a user, you have to be authenticated. But the field togglKeyreally should only be queryable by the user who that property belongs to.

I thought “well, let’s just do a custom directive for this”, but after studying the documentation I am in a bit of a bind:

  • the validator directive does not have access to the resolved value
  • the transformer cannot be async (which i would need to do, to check if the currentUser is also the one who the record is for).

Any ideas how to resolve this?

1 Like

Got something working here - let me know if there is a better way!

When inspecting the context that I receive in the validator directive, there is the context.params.query which contains the original GraphQL query which itself contains the id of the user that I want to query.

So, with a little regex magic I can extract the ID and then compare it to the id of the context.currentUser.

This is what my directive now looks like:

import {
} from '@redwoodjs/graphql-server'

export const schema = gql`
  Use @requireSameUser to validate access to a field, query or mutation.
  directive @requireSameUser on FIELD_DEFINITION

const validate: ValidatorDirectiveFunc = ({ context }) => {
  const regex = /id:\s*"([a-f\d-]+)"/;

  // Use the match method to extract the id value
  const match = context.params.query.match(regex);

  // The extracted id value will be in the second element of the match array
  const requestedUserId = match ? match[1] : null;

  if (requestedUserId !== context.currentUser?.id) throw new RedwoodGraphQLError("Sorry, can't let you do this.")

const requireSameUser = createValidatorDirective(schema, validate)

export default requireSameUser
1 Like

You could do something much simpler.

Instead of querying for a user by and seeing if the user id is the current user via a directive — just create an authenticated service called “me” or something that takes no params.

Then in the service fetch the user profile data for the

Or if you want to protect any other service never pass in the user id — just get it from the context and use it in your data fetch.


Wow, yeah that is a much more elegant solution. For others, the me service looks like this:

export const me: QueryResolvers["me"] = () => {
  return db.user.findUniqueOrThrow({
    where: { id: context.currentUser?.id }

TIL: The context is also available in the services!

In general, I suppose I need to create more GQL types for specific use cases. I guess I was abusing the default User type before.

Thanks so much!


The solution did work for me.
Just beware that when I imported the context, I needed to restart the server.

import { context } from '@redwoodjs/graphql-server'
1 Like