Code Monkey home page Code Monkey logo

graphql-shield's Introduction

graphql-shield

CircleCI codecov npm version Backers on Open CollectiveSponsors on Open Collective

GraphQL Server permissions as another layer of abstraction!

Overview

GraphQL Shield helps you create a permission layer for your application. Using an intuitive rule-API, you'll gain the power of the shield engine on every request and reduce the load time of every request with smart caching. This way you can make sure your application will remain quick, and no internal data will be exposed.

Features

  • βœ‚οΈ Flexible: Based on GraphQL Middleware.
  • 🀝 Compatible: Works with all GraphQL Servers.
  • πŸš€ Smart: Intelligent V8 Shield engine caches all your requests to prevent any unnecessary load.
  • 🎯 Per-Type or Per-Field: Write permissions for your schema, types or specific fields (check the example below).

Documentation

You can find extensive documentation at https://the-guild.dev/graphql/shield.

Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our backers! πŸ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

Contributing

We are always looking for people to help us grow graphql-shield! If you have an issue, feature request, or pull request, let us know! For information about development setup and more, see CONTRIBUTING.md.

License

MIT @ Matic Zavadlal

graphql-shield's People

Contributors

apalm avatar charlypoly avatar christianjacobsen avatar corim avatar cvblixen avatar dependabot[bot] avatar dimatill avatar dusanmigra avatar ecwyne avatar github-actions[bot] avatar katt avatar kaveet avatar lynxtaa avatar marktani avatar maticzav avatar monkeywithacupcake avatar n1ru4l avatar p4sca1 avatar pabloszx avatar paulooze avatar rankun203 avatar rdela avatar renovate-bot avatar robhanlon22 avatar ruairidhwm avatar ryanwilsonperkin avatar saihaj avatar sapkra avatar tuvalsimha avatar victormonterrosoqb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-shield's Issues

Custom errors for rules and global fallback

Hi @maticzav! First of all thanks for the awesome library!

I have few questions/suggestions about CustomErrors:

  1. Is there a way to specify CustomError that will be returned from shield in case if permissions checks are failed?

Example:
I have isAuthenticated rule

export default rule()((parent, args, { user }) => Boolean(user));

I want to return my custom 401 error like this

import { SevenBoom } from 'graphql-apollo-errors';

rule(null, { 
  customError: SevenBoom.unauthorized('You are not authenticated')
})((parent, args, { user }) => Boolean(user))
  1. Is there a way to specify global CustomError instead of https://github.com/maticzav/graphql-shield/blob/master/src/index.ts#L234 which will be used in case if there is no rule specific error?

Example:

import { SevenBoom } from 'graphql-apollo-errors';

shield({ /* Rules… */ }, {
  customError: SevenBoom.forbidden('You are not allowed to do this action.')
})

I can implement this and looks like it is not a breaking change.

Just want to clarify if there is no way to do this in current version of the library?

Let me know if you have any questions. Thanks!

Errors thrown in resolver result in "Insufficient Permissions" error

First of all, just wanted to add that I love the simplicity of this module, it's certainly made setting up auth in my latest graphql project simpler. Quick question:

I noticed that any errors raised in within my resolvers result in a PermissionError -- is this the intended behavior?

I'm not currently doing anything to handle the errors, so perhaps I should be doing something to deal with them more gracefully; but regardless, I was expecting to receive/log/crash with the original error.

Schema documentation and Client-side logic

This looks really awesome, especially with the new features coming in 3.0!

I'm currently using schema directives to enforce permissions based on Apollo's docs. I've added two features that really benefit my app:

  1. The directive appends the field description with a markdown-rich explanation of the permissions rules so you can see the requirements right in GraphiQL/Playground.
  2. It generates (hackishly, and only in dev environment) TS definitions and objects that contain information about permissions rules so the client can proactively exclude fields or disable queries/mutations it predicts may be unauthorized.

So, I have a couple questions. I'm also happy to contribute to any of these features if they seem possible and interesting.

  1. I'm not sure how the introspection query works under the hood, but would it be possible for this library to append information to the descriptions of fields based on permissions rules?
  2. Any thoughts on how to expose the permissions rules to client-side logic? Obviously some require data from the query itself, but at least simple access rules, like isAuthenticated and isAdmin etc. could be derived.

Field type permissions

Hi! I have tested permissions applied to type which is returned from query and it seems not to work when resolvers for type were not explicitly defined:
for e.g. this works when I do query me:

const resolvers = {
  Query: {
    me: (_, args, ctx) => ctx.user;
  },
  User: {
    name(parent, args, ctx) { return parent.name; }
  }
}

const permissions = shield({
  User: {
    name: allow
  }
})

and this doesn't, although it has allow rule:

const resolvers = {
  Query: {
    me: (_, args, ctx) => ctx.user;
  }
}

const permissions = shield({
  User: {
    name: allow
  }
})

Always getting Not Authorised! error.

Add support for resolver options

export interface IResolverOptions {
  resolve?: IFieldResolver<any, any>;
  subscribe?: IFieldResolver<any, any>;
  __resolveType?: GraphQLTypeResolver<any, any>;
  __isTypeOf?: GraphQLIsTypeOfFn<any, any>;
}

Cacheing

We do caching regardless of if the rule uses field specific data like parent, args or info

how to get passport's Auth info in this middleware

ref: dimatill/graphql-middleware#8 (comment)

hi all, i use express + passport-oauth2 in my web.
and i want to use graphql to wrap exist restapi, with permission check.

i follow the examples/permissions , but in this line

https://github.com/prismagraphql/graphql-middleware/blob/6889d229181e49b4e8711d22a960900b103c2632/examples/permissions/index.js#L40

the context.request.isAuthenticated() alway false,
and i debug into the code, it looks like the this have nothing about auth info.

anybody can tell me how to use this library whit passport ?

How to add a rule for a all List?

When I have a query which returns a list, if the first response is good, it's the same for all object in the list, ex:

type Query {
  users: [User!]!
}

rules:

shield(
  {
    User: {
      email: isOwner
    }
  }
)

The rule is just for logic to check if the user authenticated is the same as the requested to allow the request to return the field.

I notice if I add a parameter to the query to change the order, the query is directly denied.

Middleware order in forward binding example

I use with-graphql-middleware-forward-binding example.
Order of middlewares not working for me. Shield just not triggered:

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  resolverValidationOptions: {
    requireResolversForResolveType: false
  },
  middlewares: [permissions, forwardMiddleware],
  context: req => ({
    ...req,
    db: new Prisma({
      endpoint: process.env.PRISMA_ENDPOINT,
      debug: false
    })
  })
})

My shield:

export const permissions = shield(
  {
    Mutation: {
      updateUser: rules.isSelf,
    },
  }
)

Forwards:

export const forwardMiddleware = forward(
  'Mutation.updateUser',
)('db')

Also i have something my own resolvers:

import { Query } from './Query'
import { auth } from './Mutation/auth'

export default {
  Query,
  Mutation: {
    ...auth
  }
}

So i change
middlewares: [permissions, forwardMiddleware],
to
middlewares: [forwardMiddleware, permissions],
And shield start catching queries. Maybe i don't understand something and this is expected behavior?

Add fragments support in rules

Add support for fragments in rules, so we can rely on nested data.

const nestedRule = rule({
  cache: 'strict',
  fragment: 'fragment UserID on User { id }',
})(async ({ id }, args, ctx, info) => {
  return somethingWithID(id)
})

Cache permissions on the same resolver level

It seems permissions are only cached when the father ran the same permission function before.
If i want to simply hide a set of fields, for unauthorized users, caching for siblings would come in handy.
like this:

export const userProfilePermissions = {
  // isOwnProfile is run 3 x currently
  email: isOwnProfile,
  phone: isOwnProfile,
  address: isOwnProfile
}

Error: Cannot find module 'chalk' when using graphql-shield in production

My Node.js app runs perfectly fine in development mode.

On running the app in production (by setting NODE_ENV to production or using npm install --production), it throws the following error:

Error: Cannot find module 'chalk'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/home/example/app/node_modules/graphql-shield/dist/src/index.js:56:15)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/home/example/app/src/graphql/index.js:1:82)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)

If I do just npm install on my production server without the --production flag, all works well but I suppose that's not a solution since I don't want to take up space installing devDependencies on my production server.

Question: How can we rely on specific fields in rules?

Hello, first of all thanks for the great lib!

I have a a question. In docs there is a rule defined and used as:

const isOwner = rule()(async (parent, args, ctx, info) => {
  return ctx.user.items.some(id => id === parent.id)
})

const permissions = shield({
  /* ... */
  User: {
    secret: isOwner
  },
})

The rule uses parent.id which is ID of user to determine if the user is a owner. From what I've been able to understand by playing with this library, we can't really rely on any field of parent.

Let's say the client queries something like:

query {
  me {
    id
    secret
  }
}

Where me is a Query which returns current user - then everything is correct. However, what if client queries a Query:

query {
  me {
    # notice the missing ID
    secret
  }
}

then the parent.id in isOwner rule is undefined and we can't correctly decide whether the user is owner or not.

How can the isOwner rule be implemented correctly? Is there even a way to do that?

Thanks!

v 1.2.6 is broken

I upgraded v.1.20 to 1.2.6 and my compiler getting error graphql-sheild not found!

Type permissions with no explicit resolvers.

A bit of context, shield is meant to be a wrapper for resolvers. Currently, the two parameters it accepts are permissions and resolvers - I think that adding typeDefs as another argument makes everything unnecessarily more complex.

The problem is that since people often only define types in typeDefs but do not resolve them in resolvers (graphql manages this for them automatically behind the scenes). When generating resolvers from permissions, I cannot tell which resolvers might exist in the end since I can obtain only the keys in defined resolvers and permissions.

Let’s say, for example, that we have such schema and permissions…

type Query {
   text: String!
   list: [String!]!
   type: Type!
}

type Mutation {
   development: String!
}

type Type {
   property: String!
   properties: [String!]!
   hiddenProperty: String!
}

schema {
   query: Query,
   mutation: Mutation
}
const _permissions = {
   Query: () => true,
   Type: {
      property: () => true,
      properties: () => true
      // hiddenProperty should by default be blacklisted
   }
}

Now we have two options for resolving Type; first, resolving it only in Query and second, resolving it under Type. Taking the first approach the exact scenario occurs, since neither resolvers nor permissions define hiddenProperty key, shield cannot make a tree this deep and hiddenProperty query is always resolved.

const _resolvers = {
   Query: {
      text: () => 'simpletext',
      list: () => ['firsttext', 'secondtext', 'thirdtext'],
      type: () => ({
         property: 'typeproperty',
         properties: [
            'firsttypeproperty',
            'secondtypeproperty',
            'thirdtypeproperty'
         ],
         hiddenProperty: 'hiddentypeproperty'
      })
   },
   Mutation: {
      development: () => 'notpublic'
   },
}

On the other hand, the following works as expected.

const _resolvers = {
   Query: {
      text: () => 'simpletext',
      list: () => ['firsttext', 'secondtext', 'thirdtext'],
      type: () => ({})
   },
   Mutation: {
      development: () => 'notpublic'
   },
   Type: {
      property: () => 'typeproperty',
      properties: () => [
         'firsttypeproperty',
         'secondtypeproperty',
         'thirdtypeproperty'
      ],
      hiddenProperty: () => 'hiddentypeproperty'
   }
}

More info about caching

How does do cache work?

How long is the cache life cycle?

Does it create a cache for each request?

Sorry for so many question... Great project!!

with apollo-server-lambda?

Hello!

is graph-shield possible to use with apollo-server-lambda?

I tried to found examples on google how to implement with apollo-server-lambda, but no luck :(

is it possible?

Rationale

Hi,

I fail to understand what is the use of your project. Is it some kind of firewall?

Could you give an example of what it protects from?

Thanks.

v2.0 works as expected :-) debug: property.

Hi,

I sort of missed the update and just noticed it now.

I just wanted to say that everything seems to be working as planned! Great update and thanks for your time and effort.

Your implementation of passing {debug: true} works great for me to allow graphql-errors to pick up the error message that I originally threw inside my resolvers / permissions.

Maybe the property name should be allowExternalErrors or something similar as debug seems to shout something to do with debugging.

But hey, it works!

Thanks once again!

Should throw 'ForbiddenError' error

Apollo Server 2.0 added the ability to add error codes. Out of the box there are three error code types:

  • AuthenticationErrorβ€Šβ€”β€Šfor authentication failures
  • ForbiddenErrorβ€Šβ€”β€Šfor authorization failures
  • UserInputErrorβ€Šβ€”β€Šfor validation errors on user input

I propose that graphql-shield should throw ForbiddenError. This results in a more meaningful, standardised response on the client.

from:

extensions: { code :"INTERNAL_SERVER_ERROR" },
message: "Not Authorised!"

to:

extensions: { code :"FORBIDDEN" },
message: "Not Authorised!"

ForbiddenError can be imported from apollo-server:

import { ForbiddenError } from 'apollo-server'

I have a current workaround by setting allowExternalErrors to true and throwing this error from the rule resolver.

Reusable rules: hasRole functionality

I just updated to graphql-shield v2.0.6 and now I get this error on running my Node.js app:

RangeError: Maximum call stack size exceeded
    at convertRulesToMiddleware (/path-to-server/server/node_modules/graphql-shield/dist/index.js:1:1)
    at leafs.reduce (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:84)
    at Array.reduce (<anonymous>)
    at convertRulesToMiddleware (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:30)
    at leafs.reduce (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:84)
    at Array.reduce (<anonymous>)
    at convertRulesToMiddleware (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:30)
    at leafs.reduce (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:84)
    at Array.reduce (<anonymous>)
    at convertRulesToMiddleware (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:30)
    at leafs.reduce (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:84)
    at Array.reduce (<anonymous>)
    at convertRulesToMiddleware (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:30)
    at leafs.reduce (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:84)
    at Array.reduce (<anonymous>)
    at convertRulesToMiddleware (/path-to-server/server/node_modules/graphql-shield/dist/index.js:232:30)

Authentication and Autherization for subscriptions

First of all thanks for this amazing library. Thanks a lot. The docs for authorization in Apollo docs suck

I have a doubt, is it possible to authorize subscriptions using graphql-shield? Mutations are also possible, right?

Updating "context" on the permission layer

Thank you for this helpful tool!

I am just curious are we allowed by shield principle to update the "context" object from the permissions layer then passing it to the resolvers?

Deny reconnect node to other users when use forward to db

In https://github.com/maticzav/graphql-shield/tree/master/examples/with-graphql-middleware-forward-binding example i think any user can connect him posts to another.
I use graphql-middleware-forward-binding to forward request to db. And i trying to minificate wrapping of generated prisma resolvers by using forwarding and some rules.
So my question is - what the best case of using this package if i want to prevent node reconnecting to other users if i forward request to prisma? I understand what i can just wrap it to another resolvers and prevent owner field to modify, but how can it be done using this package?
For example i have that datamodel.graphql:

type User implements Node {
  id: ID! @unique
  competitions: [Competition!]! @relation(name: "UserCompetition")
}

type Competition implements Node {
  id: ID! @unique
  owner: User! @relation(name: "UserCompetition")
}

Now i forward updateCompetition:

import { forward } from 'graphql-middleware-forward-binding'

export const forwardMiddleware = forward(
  'Mutation.updateCompetition',
)('db')

And want to prevent reconnecting user competition to another user by modify owner field:

import { shield } from 'graphql-shield'
import * as rules from './rules'

export const permissions = shield(
  {
    Mutation: {
      updateCompetition: rules.denyChangeOwner,
    },
  },
)

default rules

For authentication purposes, it's a pain to add a rule on every schema entity.

What about a default rule parameter?

Feature Request: Whitelisting instead of Blacklisting

Hey, I absolutely love this. Thank you so much for your hard work on graphql-shield. One thing that I feel would be super useful is a whitelisting in place of blacklisting feature. Locking everything down and then explicitly exposing access would go a long way to help people develop better habits, be more involved with this part of the process and I think create all around more secure systems.

Consider allowing permissions to be set on a per-field basis

Although I'm an avid user of GraphQL Shield - thank you for creating such a simple means of implementing permissions! - something that has always irked me is that when you implement permissions on a by-type basis, you effectively lose the relational power of GraphQL. Perhaps I'm wrong on this, but this is the issue I see, illustrated with an example:

  1. Developer of a social & eCommerce website implements a query to allow fetching user details for a user profile page , something like this:
{
  user (input: UserWhereUniqueInput) {
    name
    age
  }
}
  1. Developer sets a basic isAuthenticated permission on the query to ensure that only logged in users can run this query, but adds no permissions beyond that

  2. A malicious user pokes around the publicly available schema, and finds out that the website stores payment information as CreditCard nodes that have one-to-one relations with User nodes

  3. Malicious user simply edits the query to the following, and can now steal people's credit cards:

{
  user (input: UserWhereUniqueInput) {
    name
    age
    creditCard {
      number
      securityCode
    }
  }
}

I see two solutions to this:

  1. Forcibly set the info of the query to return a pre-determined result
  2. Create a permissions system that parses info, compares it to one of several templates based on the user's permissions level, and either throws an error or lets the query through

Since the first solution effectively turns GraphQL into a regular REST endpoint, thereby defeating the purpose, I ended up rolling my own solution that implements #2 using graphql-fields. It even allows for functions to be passed in that can evaluate the input at runtime, and determine whether to authorize the operation or not based on the actual query input. Here's an example with a mutation:

export default {
  Mutation: {
    createCollectionAsPartner: rule()(
      async (parent, { collectionCreateInput }, ctx: Context, info) => {

        const permissionFunction: PermissionFunction = (): boolean => {
          return collectionCreateInput.collectionVersions.create.deleted !== false;
        };

        const permissionDefinition: PermissionDefinition = {
          collectionVersions: {
            create: {
              name: true,
              deleted: permissionFunction,
              externalFiles: {
                create: {
                  applicationType: true,
                },
              },
            },
          },
        };

        const verified = verifyMutationPermissions(
          collectionCreateInput,
          permissionDefinition,
          'createCollectionAsPartner'
        );

        return verified;
      }
    ),
  },
};

Using this definition, this mutation would work, because name is defined as true in the PermissionDefinition object:

mutation {
  createCollectionAsPartner(collectionCreateInput: {collectionVersions: {create: { name: "12345"}}})
}

While this one would not, because approvedManually is not defined in the PermissionDefinition object:

mutation {
  createCollectionAsPartner(collectionCreateInput: {collectionVersions: {create: { approvedManually:true}}})
}

This example is based on typings generated by Prisma, and limits what kind of input can be passed in when creating this type to the ones defined and equal to true in the PermissionDefinition object. If a field is not defined in the object, or is defined but as either false or a sync/async function that resolves to false at runtime, the operation is denied. The end result is extremely granular control over what is and isn't allowed, without sacrificing the ability to query/mutate by relations, the greatest strength in GraphQL.

Although I wouldn't necessarily expect this to make it into the native library, I'd love to hear everyone's thoughts on this approach! I was surprised to see how little attention this critical security issue is getting within the GraphQL community, but it's possible that I'm just doing something totally wrong and this isn't a problem with a correct setup.

Way to override the logger ?

Hi,

Does anyone know if there is a way to override the standard behaviour of throwing the PermissionError or at least some point to intercept it ?

I am using Log4js to do my logging so I would prefer to intercept these errors.

Anyone have any ideas ?

Parent is undefined

I'm following the examples for setting up with Prisma (using the Prisma graphql-authentication example) and everything is working great except when I try to use parent in a rule to establish user ownership.

const isOwner = rule()(async (parent, args, ctx, info) => {
  // Here, ctx contains my proper user object but parent is always undefined
  // without this permission, the yoga resolves the mutation just fine and the updated post is returned
  return ctx.user.items.some(id => id === parent.id)
})

const permissions = shield({
  Mutation: {
    updatePost: or(isAdmin, and(isOwner, isEditor))
  },
})

What I see is that the isOwner rule is being called before my updatePost resolver. Is this the intended behavior? Kinda makes sense not to hit the database if not authorized but then I have no chance to check the ownership of the post.

Does anyone know how parent is supposed to be populated? @maticzav explains nicely in dimatill/graphql-middleware#19 that parent is the "result of the previous function. GraphQL works recursively by calling successive types determined by the schema. It starts off with undefined and continues execution down the chain forwarding the result of the previous resolver to the new one." Ok. But my resolver is never called. What am I doing wrong?

Thanks so much!!

GraphQL Shield 2.0

Where is graphql-shield headed

First, thanks for all the great feedback you've all given me so far. While listening to you and thinking about what I want and how I would like to use graphql-shield in my projects, I came to some conclusions, which will lead the second version of this package.

Whitelisting

The most requested feature and I, in my opinion, the most important one is whitelisting. Whitelisting, in comparison to blacklisting, requires all the exposed queries to be explicitly allowed in order to be used. Adoption of whitelisting also brings a lot easier stage separation as queries/mutations can be allowed in the development phase and restricted in production.

interface Options {
   debug: true // -> makes all the queries "available"
   cache: true
}

Nesting permissions

Currently, graphql-shield only supports nesting permissions using type-specific permissions, which get evaluated during execution chain.

const permissions = {
   Query: {
      me: authenticated
   },
   Me: {
      id: isMe,
      name: isMe,
      secret: isMe
   }
}

I think that the best approach to tackle this problem is by making possible lists of permissions.

const permissions = {
   Query: {
      me: [authenticated, isMe]
   },
}

As things get more complicated you might as well want to make some permissions optional (OR), which would require helper functions like oneOf and all to make it all possible.

const permissions = {
   Query: {
      posts: oneOf(isAdmin, isEditor, isOwner),
      oneTimeLatter: all(isAuthenticated, latterNotRead)
   }
}

This is also the solution I am aiming for.

Allow entire type permissions

Right now, you can only restrict certain fields and the entire types altogether. By introducing whitelisting instead of blacklisting this feature becomes essential as having to explicitly allow each field for each type is all too much work. In my opinion, making Type general permissions available would perfectly solve this problem.

const permissions = {
   Query: {
      me: auth
   },
   Me: allowAllFields
}

Debugging

I think that most of the functionality should be directed to developers during the development stage. By introducing the right tools to make permission handling as easy as possible, we can make an actual difference with graphql-shield.

Few ideas:

  • Summary of all permissions in debug mode.
  • Stage separation (as mentioned above) which would allow access to non-whitelisted queries to test and develop new permissions.

Use graphql-shield with graphql and express-graphql

Hi everyone,
I'm doing a project that uses graphql but I use graphql with express-graphql. But I want to apply graphql-shield to my project.
Please help me!
Thanks for the support!
import { GraphQLSchema, GraphQLObjectType, } from 'graphql';
import { user, users, usersByRole } from './queries/UserQueries';
const queryType = new GraphQLObjectType({ name: 'QueryType', description: 'The root for all queries available.', fields: { users, user, usersByRole, } });
// Creating schema
const schema = new GraphQLSchema({ query: queryType, });
export const permission = shield({ Query: queryType, });
export default schema;

how to merge multi permission into one?

follow the README, we have to defined the big permission object like this:

const permissions = shield({
  Query: {
    frontPage: not(isAuthenticated),
    fruits: and(isAuthenticated, or(isAdmin, isEditor)),
    customers: and(isAuthenticated, isAdmin)
  },
  Mutation: {
    addFruitToBasket: isAuthenticated,
  },
  Fruit: isAuthenticated,
  Cusomer: isAdmin
})

could you give something like merge

const permissions = mergeShield({
    1Resolve,
    2Resolve,
    ...
});

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two-Factor Authentication, make configure the auth-only level is supported. semantic-release cannot publish with the default auth-and-writes level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

Custom error message

Is it possible to modify the error object?

{
  "data": null,
  "errors": [
    {
      "message": "Insufficient Permissions.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "getSurveys"
      ]
    }
  ]
}

Or can we directly use other error handler like apollo-errors instead of using the default "Insufficient permission"

Thanks for the assist!

Can't handle mixed query

code like this:

const isAuthenticated = rule()(async (parent, args, ctx, info) => {
  console.log("call isAuthenticated args = ", args)
  return true
})
const permissions = shield({
  Query: {
    feed: isAuthenticated,
    post: isAuthenticated,
  },
})

If the query like this, the isAuthenticated only be called once !!!

query{
  feed{
    id
    text
  }
  post(id:"cjk9uyalu00110803ow0wrxwm"){
    id
    title
  }
}

Context passing - cache

  • Support chains
  • Caching of previous requests to prevent multiple identical requests in one run

Can Shield help ensure ownership?

Thanks for maintaining a great project :)

I'm hoping to use graphql-shield to lock down my API. Currently I'm using https://github.com/maticzav/graphql-middleware-forward-binding to forward requests to the auto-generated resolvers.

Based on your post (https://medium.com/@maticzav/graphql-shield-9d1e02520e35), does the isCustomer function ensure that customers can only add items to their own basket? Or how would you add that logic to the function?

When calling addItemToBasket, are the args of that mutation passed along to isCustomer?

I'm using a JWT in the auth header, with a unique ID in the payload. Does that come through in the ctx variable in some way?

Thanks!

Add tests

  • Cache
  • Basic merging
  • Object resolvers, Fragment resolvers, Regular resolvers

Fine-grained permission control?

I'm wondering if it's possible to return different result for different users.
for example, i want to only permit users to see the posts they've created themselves. Should this be managed and can this be managed by graphql-shield?

Many thanks.

"Not Authorised!" on a field make the containing object null

First of all I think that graphql-shield add a clean, generic and maintainable security layer to graphql.
It don't replace ad-hoc fine-grained security check in some resolver for special cases but make easy to add uniform basic access control on all your schema.
So kudos to you!

I'm implementing a field level access policies with graphql-shield but I'm having a strange issue.
When a field is "Not Authorised!" the parent object is set to null.
Here is an example.

Permissions:
const permissions = shield({ Query: { node: allow, }, User: { name: allow, secret: deny } });

Query:
{ node (id: 'myId') { ... on User { name, secret } } }

Expected result:
{ "data": { "node": { name: "My name" } }, "errors": [ { "message": "Not Authorised!", "locations": [ { "line": 31, "column": 3 } ], "path": [ "node", "secret" ] } ] }

Actual result:
{ "data": { "node": null }, "errors": [ { "message": "Not Authorised!", "locations": [ { "line": 31, "column": 3 } ], "path": [ "node", "secret" ] } ] }

It's not an errorPolicy issue on the client because this is extracted from the raw http response.
Only parent object is set to null.
A connection query has all fields normally returned but edges are like this
edges { edge { node: null }, edge { node: null }, edge { node: null }, edge { node: null } }

I'd like to adopt graphql-shield so let me know if I can help to solve this issue.
Thanks.

Permissions on Input Types

A use case I'm interested in is putting permissions on input types and individual fields of input types. This would simplify mutation permissions because you could use a generic mutation like updateUser but limit access to modifying certain fields of User.

Is this supported or possible to add? I'd be happy to contribute if interested.

Is there a "shield way" to make sure current user is creator for update request?

Let's assume I have Users and Posts, and want to create a UpdatePost mutation and also want to make sure, that only the creator of the post can edit it. I could take the userid from the context (which comes from token auth) and match it with the authorId. But is there a more elegant way to do this via a middleware with graphql-shield?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.