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.

graphql-shield + Apollo Federation

See original GitHub issue

Question about GraphQL Shield

I’ve setup graphql-shield with a federated graph. After the permission rule isAuthenticated returns an error, the resolver of the account service is hit but the data returned for the me query is null. The expected behavior would be that the account service resolver is not hit and the error the permission rule is throwing is returned.

Does graphql-shield support federated graphs? Am I missing something in the implementation?

Server

const { ApolloServer } = require("apollo-server");
const { ApolloGateway } = require("@apollo/gateway");
const { applyMiddleware } = require("graphql-middleware");
const { formatError } = require("apollo-errors");
const { permissions } = require("./middlewares");

const gateway = new ApolloGateway({
  serviceList: [
    { name: "account-service", url: "http://localhost:4001/graphql" }
  ]
});

(async () => {
  const gw = await gateway.load();
  const { schema } = applyMiddleware(gw.schema, permissions);
  const { executor } = gw;
  const server = new ApolloServer({
    schema,
    executor,
    formatError
  });
  server.listen().then(({ url }) => {
    console.log(`🚀 Server ready at ${url}`);
  });
})();

Permissions

const { shield } = require("graphql-shield");
const Rules = require("./rules");

const permissions = shield(
  {
    Query: {
      me: Rules.isAuthenticated
    }
  },
  {
    allowExternalErrors: true,
    debug: true
  }
);

Rule

const { rule } = require("graphql-shield");
const Errors = require("../../../misc/errors");

const isAuthenticated = rule()(async (parent, args, context) => {
  return new Errors.NotAuthorizedError();
});
  • I have checked other questions and found none that matches mine.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:13

github_iconTop GitHub Comments

7reactions
harri121commented, Jul 31, 2019

@maticzav Sure

Approach

1️⃣The gateway service fetches the user from the request auth token. 2️⃣The user is then passed to the sub services via the request header. 3️⃣Get the user from the request header in the sub service 4️⃣Use the user in your permission rules

Gateway service

const { ApolloServer } = require("apollo-server");
const { ApolloGateway, RemoteGraphQLDataSource } = require("@apollo/gateway");

const gateway = new ApolloGateway({
  serviceList: [
    { name: "account-service", url: "http://localhost:4001/graphql" }
  ],
  buildService({ name, url }) {
    return new RemoteGraphQLDataSource({
      url,
      willSendRequest({ request, context }) {
        if (context.user) {
          // 2️⃣pass the user to the sub service
          request.http.headers.set("user", context.user);
        }
      }
    });
  }
});

(async () => {
  const { schema, executor } = await gateway.load();
  const server = new ApolloServer({
    schema,
    executor,
    context: ({req}) => {
       //1️⃣ get user from auth token 
       return {
          user
       }
    }
  });
  server.listen().then(({ url }) => {
    console.log(`🚀 Server ready at ${url}`);
  });
})();

Sub service

const fs = require("fs");
const express = require("express");
const { ApolloServer, gql } = require("apollo-server-express");
const { buildFederatedSchema } = require("@apollo/federation");
const { applyMiddleware } = require("graphql-middleware");
const { permissions } = require("./middlewares");
const { resolvers } = require("./resolvers");

const typeDefs = gql`
  ${fs.readFileSync(__dirname.concat("/schema.graphql"), "utf8")}
`;

const schema = buildFederatedSchema([
  {
    typeDefs,
    resolvers
  }
]);

const schemaMiddleware = applyMiddleware(schema, permissions);
const server = new ApolloServer({
  schema: schemaMiddleware,
  context: ({ req }) => {
    // 3️⃣get the user
    if (!req.headers["user"]) {
      return {};
    }
    const user = req.headers["user"];
    return {
      user
    };
  }
});

const app = express();
server.applyMiddleware({ app, path: "/graphql" });
app.listen({ port: 4001 }, () => console.log("Account service ready!"));
1reaction
dwelch2344commented, Feb 23, 2020

@donedgardo I guess it would. My sublevel services can only be accessed from within my k8s cluster, that’s why this solution is working for me. You can also set the Authorization header instead of the user directly and check for it in each sublevel service.

@donedgardo Please please please don’t do this. This is essentially the equivalent of relying on network security. Yes, the K8s network boundary is a lot easier to lock down, but if you’re building a distributed system don’t just take authentication as granted. Forward the auth header, or at least some sort of signed message

Read more comments on GitHub >

github_iconTop Results From Across the Web

graphql-shield + Apollo Federation · Issue #456 - GitHub
I've setup graphql-shield with a federated graph. After the permission rule isAuthenticated returns an error, the resolver of the account ...
Read more >
Securing a federated graph - Apollo GraphQL Docs
As a best practice for federated graphs, Apollo recommends that subgraph services should only be queried by the gateway or Router directly. The...
Read more >
Apollo Server Federation with graphql-shield - Stack Overflow
When encountering an error, graphql-shield absorbs them, which can hide issues which you are trying to debug. This might also be a problem, ......
Read more >
auth-sample-graphql-shield - CodeSandbox
Templatefederation-sandbox; Environmentapollo. Files. src. permissions. services. demo-query.graphql. index.ts .prettierignore .prettierrc. README.md.
Read more >
Walkthrough of Using GraphQL Shield - Nordic APIs
GraphQL Shield is a library that provides a simple way to add authorization to your GraphQL server. It uses the Apollo server and...
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