Apollo Server
Apollo Server
The following example adds permissions to Apollo Server with Permit.io, and is based on Apollo's fullstack tutorial example. Once you have the code base cloned, got to Permit's connect SDK screen to add Permit to your code (steps 1-3), and continue to add access-control with Permit to the Apollo Server middleware (step 4-5). Note step 4 has multiple options, we provide examples here, and there are many other ways you can go about mapping your resources and actions to your GraphQL Schema.
1. Add the permit package to your project
npm install permitio
2. Import the package into your server
const { Permit } = require("permitio");
3. Init the permit object with the secret api key
Copy it from the code example in this page Permit connect sdk and replace it with the token placeholder in the code below
const permit = new Permit({
// in production, you might need to change this url to fit your deployment
pdp: "https://cloudpdp.api.permit.io",
// your api key
token: "permit_key_secret"
});
4 (option 1) - opertaion name to resource & action mapping
Create a Plugin to check the permissions of each request and a map of operationName to resource and action in Permit policy
const PermissionMap = {
"login": {resource: "user", action: "login"},
"logout": {resource: "user", action: "logout"},
"me": {resource: "user", action: "get"},
"launches": {resource: "launch", action: "getall"},
"getlaunch": {resource: "launch", action: "get"},
}
const permitPlugin = {
async requestDidStart(context) {
const operationName = context.request.operationName;
var userId = await getUserIdFromJWT("");
let allowed = false;
if (operationName.toLowerCase() in PermissionMap) {
const { resource, action } = PermissionMap[operationName.toLowerCase()];
allowed = await permit.check(userId, action, resource);
}
else {
console.warn('No such operation in PermissionMap', operationName);
}
if (!allowed) {
throw new Error("Not allowed");
}
},
};
Add the expected resource names and actions in the policy editor.
4 (option 2) - Operation name as resource, and operation type as action
If you prefer deducing the resource and actions with a more simple translation, you can use the following plugin instead
const permitPlugin = {
requestDidStart(requestContext) {
return {
async didResolveOperation (context) {
const op = context.operationName
var userId = await getUserIdFromJWT("");
isMutation = context.operation.operation === 'mutation'
const allowed = await permit.check(userId, isMutation? "write": "read", op.toLowerCase()) // this will look like "action: write, resource:launches" or "action: read, resource:launches"
if (!allowed) {
throw new Error("Not allowed");
}
},
}
},
}
Add the expected resource names with "read" and "write" actions in the policy editor.
5. Add the plugin to the Apollo Server plugins list
// Set up Apollo Server
const server = new ApolloServer({
debug: true,
typeDefs,
resolvers,
dataSources,
context,
introspection: true,
apollo: {
key: process.env.APOLLO_KEY,
},
plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true }), permitPlugin]
});