npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

graphql-genie-authentication

v1.1.8

Published

GraphQL Genie Authentication

Downloads

23

Readme

GraphQL Genie Authentication

npm version npm

Helps add authentication to your graphql-genie schema. Creates a @auth directive that allows role based access control down to individual fields

Installation

Assuming you already have GraphQL Genie installed.

npm install graphql-genie-authentication

or

yarn add graphql-genie-authentication

Enable plugin

import { FortuneOptions, GraphQLGenie } from 'graphql-genie';
import authPlugin from 'graphql-genie-authentication';


// typedefs must have an enum named Role
const genie = new GraphQLGenie(...args);

// or you could pass in to the constructor as part of the plugins variable
genie.use(authPlugin()); 

//get the GraphQLSchema and use it with any other tools you need
//always call getSchema after .use
const schema = genie.getSchema();

The plugin will create the auth directive and setup the necessary hooks/resolvers to allow you to decide whether or not to allow a specific request

The auth directive is defined as shown below, where defaults are arguments to the plugin.

There is also an optional rules argument, these are passed along to your authenticate function to allow additional constraints you might want to manually impose on the type or field but still define in your schema.

directive @auth(
	create: [Role] = [${defaultCreateRole}],
	read: [Role] = [${defaultReadRole}],
	update: [Role] = [${defaultUpdateRole}],
	delete: [Role] = [${defaultDeleteRole}]
	rules: [String!]
) on OBJECT | FIELD_DEFINITION

Arguments

(defaultCreateRole = 'ADMIN', defaultReadRole = 'ADMIN', defaultUpdateRole = 'ADMIN', defaultDeleteRole = 'ADMIN'): GeniePlugin

You can pass in the default required of each operation which will be used in you don't pass in the required role when using the directive. If you don't provide an argument 'ADMIN' will be the default, so make sure that is one of the roles.

Authentication Requirements

  • You can't kill a type
  • You can't bring a type back from the dead
  • You can't make a type fall in love with another type
  • No wishing for additional types
  • :)

Role enum

Your schema must have an enum named "Role". These will then be used to define necessary roles on CRUD operations. An example of roles you may want to setup.

enum Role {
	# Open to all requests
	ANY
	# Must be logged in
	USER
	# User must have created/be the type
	OWNER
	ADMIN
}

@auth directive

How the @auth directive may be used with those roles.

Note: Setting auth on a type will also wrap all the fields with the same requirements.

Note: Since auth fields have a default, when using on a field the default will override the type value, so set it again on the field even if it's the same as on tye type

# Only users can create posts, anybody can read posts, only the person who created the post can update/delete it
type Post @auth(create: USER, read: ANY, update: OWNER, delete: OWNER) {
	id: ID! @unique
	title: String!
	text: String
	# Set a rule of "SELF" here that we can look for in our authenticate function so users aren't allowed to change it to other users
	author: User @relation(name: "posts") @auth(create: USER, read: ANY, update: OWNER, delete: OWNER, rules: "SELF")
}

# Anyone can create users (aka signup), be able to see user info by default, can only update yourself, and only admins can delete
type User @auth(create: ANY, read: ANY, update: OWNER, delete: ADMIN) {
	id: ID! @unique
	username: String! @unique
	# only users can see their own email, it's not public
	email: String! @unique @auth(create: ANY, read: OWNER, update: OWNER, delete: ADMIN)
	# only admins can read password
	password: String! @auth(create: ANY, read: ADMIN, update: OWNER, delete: ADMIN)
	posts: [Post] @relation(name: "posts")
	# Only admins can alter roles, will need additional logic in authenticate function so users can only set themself to USER role
	# So we set only:USER in the rules so we can find that later in our authenticate function
	roles: [Role] @default(value: "USER") @auth(create: ANY, read: ADMIN, update: ADMIN, delete: ADMIN, rules: "only:USER")
}

authenticate function

All graphql requests must have a context with a property named authenticate. authenticate must be a function which returns (or resolves to) true if the operation is allowed. If the operation is not allowed either return/resolve to false or throw an error.

This function is where you will check the current logged in users role (or however else you want to authenticate) against the requirments setup by your schema.

An example setting up context with GraphQL Yoga

const server = new GraphQLServer({
	schema,
	context: req => ({
		...req,
		authenticate: (method, allowedRoles, record, filterRecords, updates, typeName, fieldName) => {
			return true;
		}
	})
});

The authenticate function recieves the following.

  • method: String:

    • The CRUD operation being performed
    • 'create', 'read', 'update' or 'delete'
  • allowedRoles: {create: string[]; read: string[]; update: string[]; delete: string[]; rules: string[]}

    • The configured roles allowed and rules for this type/field
    • To get just the allowed roles for the current method just do const allowedRolesForMethod: string[] = allowedRoles[method];
    • To get rules const rules: string[] = allowedRoles.rules;
  • records: object[]

    • The records (without updates) being queried/mutated.
    • You may need to look at this if you have a role like Owner to see if the current user has permission
  • filterRecords: object[]

    • In cases where records are obtained as part of filtering/finding data but aren't part of the main record they are in this argument.
      • This may contain additional info necessary when deciding if a read query is allowed when nested filtering is used in the where of a query
      • See the getUserIDsOfRequestedData function here for an example of how this might be used.
  • updates: {id: ID, replace: {}, push: {}, pull: {}}

    • example
      // ID being updated
      id: 1,
      
      // Values being replaced
      replace: { name: 'Bob' },
      
      // Values (if a scalar type) or IDs (if a object type) being pushed to a list field
      push: { posts: 1 },
      
      // Values (if a scalar type) or IDs (if a object type) being removed from a list field
      pull: { posts: [ 2, 3 ] },
  • typeName: string

    • The type being queried/mutated.
  • fieldName: string

    • The field being queried/mutated.
    • May be null if the check is just on the type
  • isFromFilter: boolean

    • true if the authentication request is a result of a filter, such as checking if a user exists with an email.

The function should also have any other constraint logic necessary, such as users not being able to create roles on themselves, or only set the author field on post to themselves

Examples

See the apollo server 2 redis jwt example for JWT authentication with users stored in the database. Uses Apollo Server 2.

See the yoga redis example for session authentication with users stored in the database. Uses GraphQL Yoga

See the yoga redis firebase example for using firebase authentication to login and control access from an external JWT provider. Uses GraphQL Yoga.

Thanks/Credit

Logo Icon made by Freepik from www.flaticon.com is licensed by CC 3.0 BY