How a user can update own profile - updateUser

In the sample GraphQL query, if I change the ID, I can change the data of each user.
How can I restrict it to my account only?

mutation{ updateUser(input: { where:{ id:5 }, data: { age:54 } }){ user{ id age } } }

1 Like

Answer also provided via the GitHub Discussion: https://github.com/strapi/strapi/discussions/8096

In this case, much like REST, you will want to use a policy. You can read more about policies and how to use them with GraphQL here:
https://strapi.io/documentation/v3.x/concepts/policies.html
https://strapi.io/documentation/v3.x/plugins/graphql.html#execute-a-policy-before-a-resolver

Unfortunately the link you provided with the solution is not available anymore.

1 Like

There was no additional context in that discussion @larse it’s the exact same as I posted here.

1 Like

@DMehaffy alright I followed the documentation and found a really nice tutorials as well.

The policy works very well for a post command. I have tried it in postman. Now I want that GraphQL use the policy as well. I read the following documentation GraphQL - Strapi Developer Documentation

Here is my code
// extensions/users-permissions/config/schema.graphql.js

module.exports = {
  resolver: {
    Mutation: {
        updateUser: {
            description: 'Update an existing user',
            policies: ['plugins::users-permissions.userUpdate'],
        },
    },
  },
};

The description is working but the policy just get ignored. (Strapi 3.5.2)
Also tried to change ‘plugins::users-permissions.userUpdate’ to ‘userUpdate’ but nothing happend.

What I do wrong?

Hello,
I think the problem is for graphql you must throw an exception not return ctx… :
To solve your problem (it work for me), modify your code as shown in this post : https://forum.strapi.io/t/correct-way-to-return-error-in-custom-service-through-graphql/1071/6
I hope this help you
Fabien

1 Like

Hey @FabienCastell,

thank you so much! With the post I was able to see and bring the pieces together. It was needed that I write my own resolver. GraphQL doesn’t work with ctx. For everyone who look also for a solution to restrict user to only edit their own profiles here is the code:

app/extensions/users-permissions/config/schema.graphql.js

const Boom = require('boom')
const _ = require('lodash');

module.exports = {
 resolver: {
  Mutation: {
  updateUser: {
    description: 'Update an existing user',
    policies: ['plugins::users-permissions.userUpdate'],
    resolver: async (obj, options, { context }) => {

      // If the user is an administrator we allow them to perform this action unrestricted
      if (context.state.user.role.name === "admin") {
        context.params = _.toPlainObject(options.input.where)
        context.request.body = _.toPlainObject(options.input.data)

        await strapi.plugins['users-permissions'].controllers.user.update(context)

        return {
          user: context.body.toJSON ? context.body.toJSON() : context.body,
        }
      }

      // The data to mutate
      const data = context.request.body; 
      // The Current User ID
      const currentUserId = context.state.user.id
      // The ID which the user like to mutate
      const userToUpdate = context.params.id

      // This limitate the user to only edit his own profile
      if (currentUserId != userToUpdate) throw Boom.unauthorized('Unable to edit this user ID')

      // Extract the fields to do some checks on it
      const { firstname, lastname } = data;

      // Check if firstname ist empty and if give badRequest
      if (firstname && firstname.trim() === "" || firstname === "") throw Boom.badRequest("Firstname is required")

      // Check if lastname ist empty and if give badRequest
      if (lastname && lastname.trim() === "" || lastname === "") throw Boom.badRequest("Lastname name is required")

      // Get the value of the where variable. In this case the user ID
      context.params = _.toPlainObject(options.input.where)

      // The Data to edit
      context.request.body = _.toPlainObject(options.input.data)

      // Edit the user data
      await strapi.plugins['users-permissions'].controllers.user.update(context)

      // Return the data
      return {
        user: context.body.toJSON ? context.body.toJSON() : context.body,
      }
    }
  },
 },
 },
};
2 Likes

Create a custom endpoint for the user.
(60) Strapi API Custom Controller || Profile/me POST - YouTube

Thanks @larse for the example. This does work fine, but it seems that the policies are still. being ignored for graphql then? Is this a bug that needs reporting?

Is not it possible to use the current resolver to handle this?

@Ben_Gannaway exactly. This was what I was facing that the policies still be ignored or maybe GraphQL runs into an error because it can’t use “ctx”. For this I wrote the custom resolver. It’s a little bit more effort when you have to write two policies for REST and GraphQL with the same logic.

@LuisAlaguna Maybe there is an other way to use { context } for in the policies without writing a custom resolver for GraphQL. Unfortunately, I can’t find anything in the documentation about this.