Skip to content
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

How to implement access control? #88

Open
ionizer opened this issue Nov 14, 2019 · 2 comments
Open

How to implement access control? #88

ionizer opened this issue Nov 14, 2019 · 2 comments

Comments

@ionizer
Copy link

ionizer commented Nov 14, 2019

Hi there!

I am trying to implement a GraphQL server with Objection.js to handle database queries, and of course this library to build the GraphQL schema. And for security measures, some access control needs to be implemented, as it is undesirable to have let's say a user querying another user's data in Users table. Assuming there are common (normal user privilege) and admin user roles in the table, the access controls should be implemented is as follows:

  1. Unauthenticated users cannot query from the table
  2. Authenticated (common) users can only query their own info
  3. Authenticated (admin) users can query all user info

How can we achieve such access control with this library?

Thanks in advance!

@ionizer
Copy link
Author

ionizer commented Nov 14, 2019

AHH! I'm terribly sorry, but I only just saw #56 and the access control example folder. But, I still don't understand what exactly needs to be done here to achieve such access control described above. But from what I understand, the objectives (according to #56) are:

  1. Pass context into graphqlHTTP's rootValue argument with onQuery function
  2. Create a custom model template class by extending Model and implement new abstract methods where it will be overridden by actual models (in this case, User model)
  3. Override the QueryBuilder of the custom model to use the new abstract methods which are used to control the query and result

Is this correct, or is there a better solution to access control?

@ionizer
Copy link
Author

ionizer commented Nov 27, 2019

I finally managed to figure something out myself:

// app.js - Main file, graphql route
app.use('/graphql', isLoggedIn, (req, res, next) => graphql({
  schema,
  context: loggedUser,
  graphiql: true,
  rootValue: {
    onQuery: async (qb) => {
      await qb.mergeContext({ loggedUser, isGraphQLQuery: true });
    },
  },
})(req, res, next));

// user.js - Model file
const { Model } = require('objection');

class User extends Model {
  static get tableName() {
    return 'user';
  }

  static get jsonSchema() {
    return {
      type: 'object',
      required: ['name'],
      properties: {
        id: { type: 'integer' },
        name: { type: 'string' },
      },
    };
  }

  static query(...args) {
    const query = super.query(...args);

    return query.onBuild((qb) => {
      const ctx = qb.context();
      const { loggedUser: user, isGraphQLQuery } = ctx;

      if (user.id !== 1 && isGraphQLQuery) return qb.where('id', user.id);
      return qb;
    });
  }
}

module.exports = User;

What this basically does is if the authenticated user's id is not 1 (let's say this one is an admin), then the user cannot query for the other user info.

Though, I really feel this is a really hacky solution as this adds another AND user.id = ? to the WHERE clause resulting in something like this when querying {user(id: 2)} when logged in as user with id 3:

SELECT id, name FROM user WHERE id = 2 AND user.id = 3

So, would anybody share an improvement to this solution or even provide a better solution?

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant