question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Auth / RBAC and graphql-shield

See original GitHub issue

@liberatiluca In https://github.com/redwoodjs/redwood/issues/806#issuecomment-656238898_ brings up graphql-shield which “helps you create a permission layer for your application”.

While Redwood services would want to protect each with the requireAuth() or requireAuth({role: 'admin'} it would be useful to protect at the GraphQL-layer as well.

He proposes an approach and looking to see if the community thinks the idea should move forward and get ideas for rolling it into RW api.

This video from Ryan Chenkie at Prisma (at ~50-51min mark) shows an example fo graphql-shield used with Auth0.

https://youtu.be/DoR7h88Xlvg?t=3051


Hello everyone!

I have successfully used graphql-shield in Redwood and I would really like to have this baked in Redwood.

To give you an example:

in the graphql sdl export an object to define the permissions too:

export const permissions = {
  Query: {
    users: isAdmin, // isAdmin returns a boolean by checking the authenticated user roles
  },
  Mutation: {},
};

new file lib/permissions.js:

import _merge from "lodash.merge";
import { deny, shield } from "graphql-shield";
import importAll from "@redwoodjs/api/importAll.macro";

const schemas = importAll("api", "graphql");

let allPermissions = {
  Query: {
    "*": deny,
  },
  Mutation: {
    "*": deny,
  },
};

Object.entries(schemas).forEach(([_, value]) => {
  if (value.permissions) {
    _merge(allPermissions, value.permissions);
  }
});

export const permissions = shield(allPermissions, {
  fallbackError: (thrownThing, parent, args, context, info) => {
    console.log(thrownThing);
    console.log(args);
    throw new Error("Not authorized!");
  },
});

in functions/graphql.js:

import { applyMiddleware } from "graphql-middleware";
import { permissions } from "src/lib/permissions";

const schema = makeMergedSchema({
  schemas,
  services: makeServices({ services }),
});

export const handler = createGraphQLHandler({
  schema: applyMiddleware(schema, permissions),
  db,
});

That’s it!

I think that this is perfect with the role-based authorization suggested here.

Would you like to have this in Redwood?

_Originally posted by @liberatiluca in https://github.com/redwoodjs/redwood/issues/806#issuecomment-656238898_

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
dthyressoncommented, Sep 28, 2020

Had a quick read through https://the-guild.dev/blog/graphql-modules-auth and will likely read several more time.

The section The Future of Authentication with GraphQL-Modules and GraphQL @directives and that approach seems most appealing.

type Mutation {
  publishArticle(title: String!, content: String!): Article!
    @auth
    @protect(role: "EDITOR")
}
type Query {
  me: User @auth
}

Where @auth and @protect could call auth’s requireAuth() such that the method to protect a service/function would be the very same one used to protect the graphql.

What i did not see though – which graphql-shield can provide very quickly – is a deny * to lock down all graphql, open up the resolvers you want, and then let requireAuth() (if needed) take over from there.

Now that I have used graphql-shield a but, I understand more what @liberatiluca suggests:

  • include a blanket deny all rule
  • in each SDL declare permissions with query and mutation rules (by allowing certain resolvers or something that can check auth or roles)
export const permissions = {
  Query: {
    users: requireAuth({roles: 'admin'}), 
  },
  Mutation: {},
};
  • the /lib/permissions assembles all the permission in each sdl and merges with the blanket all permission rule
  • applyMiddleware as in
export const handler = createGraphQLHandler({
  schema: applyMiddleware(
    makeMergedSchema({
      schemas,
      services: makeServices({ services }),
    }),
    permissions
  ),
  cors: {
    origin: '*',
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    preflightContinue: false,
    optionsSuccessStatus: 204,
  },
  onException: () => {
    // Disconnect from your database with an unhandled exception.
    db.$disconnect()
  },
})

The import services from 'src/services/**/*.{js,ts}' has replaced import importAll from "@redwoodjs/api/importAll.macro"; should should be easier to iterate the schemas and fetch each permissions

  • then permissions could be added to the sdl generator

I will try to test to see if the same requireAuth() can be used here – or not. Because it relies on context.currentUser I hope it can.

0reactions
dthyressoncommented, Apr 6, 2021
Read more comments on GitHub >

github_iconTop Results From Across the Web

Walkthrough of Using GraphQL Shield - Nordic APIs
Here we walk through using GraphQL Shield, a free open-source middleware you can use to add role-based access control to a GraphQL endpoint....
Read more >
Securing a GraphQL API with Auth0 + GraphQL Shield - UDig
Navigate to the settings tab and scroll down to RBAC settings. Make sure that the Enable RBAC and Add Permissions in the Access...
Read more >
A complete guide to permissions in a GraphQL API
This guide shows you how to use GraphQL directives, GraphQL middleware resolvers, and the GraphQL shield library to implement permissions.
Read more >
Authorization with GraphQL Shield - YouTube
In this video we'll explore some of the logic and input rules that come with GraphQL Shield to protect against unwanted requests.
Read more >
Setting Up Authentication and Authorization with Apollo ...
When building out a distributed GraphQL architecture with Apollo Federation, we will often need to limit query access based on who requested ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found