graphql-auth-directive v0.5.1
graphql-auth-directive
GraphQL @auth directive that protects resources from unauthenticated and unauthorized access.
Inspired by TypeGraphQL and GraphQL Tools.
:warning: Under development
:wave: Any help is appreciated
Installation
npm install graphql-auth-directive
# or
yarn add graphql-auth-directiveUsage
Note: See examples directory
Add
@authdirective to GraphQL schema:Note:
on OBJECT | FIELD | FIELD_DEFINITIONtype Example @auth { unprotected: String! adminProtected: String! @auth(roles: [ADMIN]) } type Query { unprotected: String! protected: String! @auth adminRoleProtected: String! @auth(roles: [ADMIN]) adminOrModeratorRolesProtected: String! @auth(roles: [ADMIN, MODERATOR]) viewPermissionProtected: String! @auth(permissions: [VIEW]) viewOrEditPermissionsProtected: String! @auth(permissions: [VIEW, EDIT]) roleAndPermissionProtected: String! @auth(roles: [ADMIN], permissions: [VIEW]) # ... } type Mutation { # Same as Query } type Subscription { # Same as Query }Build
authdirective and createGraphQLschema:import { buildAuthDirective, defaultAuthFn } from 'graphql-auth-directive'; import { makeExecutableSchema } from '@graphql-tools/schema'; import { ApolloServer } from 'apollo-server'; import { typeDefs } from './typeDefs'; import { resolvers } from './resolvers'; // Build auth directive const authDirective = buildAuthDirective({ auth: defaultAuthFn // Auth procedure (default or custom) // ... More options }); // Build schema let schema = makeExecutableSchema({ typeDefs: [authDirective.typeDefs, typeDefs], // TypeDefs resolvers // Resolvers }); schema = authDirective.transformer(schema); // Transform schema // Build and start server const server = new ApolloServer({ schema, context: () => { /* ... */ } }); server .listen() .then((serverInfo) => console.info(`Server started at ${serverInfo.url}`));Warning:
defaultAuthFnrequires a context of the following type:{ user?: { roles: string[] | number[]; permissions: string[] | number[]; }; /* ... */ }If
defaultAuthFndoes not match your configuration or you want more control, you can fully customize theauthprocedure. See Custom Auth procedure for more information.
Options
| Name | Type | Default Value | Description |
|---|---|---|---|
name | string | auth | Directive name. |
auth | Auth<TContext, TRole, TPermission> | Auth function (AuthFn<TContext, TRole, TPermission>) or class (AuthFnClass<TContext, TRole, TPermission>). | |
authMode | 'ERROR' \| 'NULL' | ERROR | Auth mode if access is not granted. ERROR throws an error. NULL returns null. |
roles | { enumName?: string, default?: TRole \| TRole[] } | { enumName: undefined, default: undefined } | Roles configuration. enumName is the enum name for roles array type, default is String. default is the default value, default to []. |
permissions | { enumName?: string, default?: TPermission \| TPermission[] } | { enumName: undefined, default: undefined } | Permissions configuration. enumName is the enum name for permissions array type, default is String. default is the default value, default to []. |
authenticationError | ClassTypeEmptyConstructor<Error> | AuthenticationError | Authentication error class. An error class must extends Error. |
authorizationError | ClassTypeEmptyConstructor<Error> | AuthorizationError | Authorization error class. An error class must extends Error. |
container | ContainerType | IOCContainer | Dependency injection container. |
Custom Auth procedure
Warning:
authmust returnbooleanorPromise<boolean>, wheretrueindicates that access has been granted andfalsethat is denied
You can fully customize the auth procedure by providing a function or class when building the directive.
import { buildAuthDirective } from 'graphql-auth-directive';
import { myAuth } from './myAuth';
// Build auth directive
const authDirective = buildAuthDirective({
auth: myAuth // Custom auth procedure
});AuthFn function
import type { AuthFn } from 'graphql-auth-directive';
import type { Context } from './Context'; // Your context type
import type { Roles, Permissions } from './User'; // Your roles and permissions enum
export const myAuthFn: AuthFn<Context, Roles, Permissions> = (
{ context: { user } }, // Context
{ roles, permissions } // @auth(roles: [...], permissions: [...])
) : boolean | Promise<boolean> => {
/* ... */
};AuthFnClass class
Note: Class based
authcan leverage Dependency Injection (DI) mechanism. To enable DI mechanism register your OCI Container when building the directive:buildAuthDirective({ ..., container: MyContainer });
import type { AuthFnClass } from 'graphql-auth-directive';
import type { Context } from './Context'; // Your context type
import type { Roles, Permissions } from './User'; // Your roles and permissions enum
export class MyAuthFnClass implements AuthFnClass<Context, UserRoles, Permissions> {
public auth(
{ context: { user } }, // Context
{ roles, permissions } // @auth(roles: [...], permissions: [...])
): boolean | Promise<boolean> {
/* ... */
}
}Integrations
TypeGraphQL
See typegraphql example for more information.
Why another GraphQL Auth Directive?
Similar libraries are unmaintained and use an old (and deprecated) version of graphql-tools. Moreover this library tries to be as most modular as possible, giving the user the ability to configure the directive as much as possible.
Similar libraries:
Contributing
I would love to see your contribution :heart:
See CONTRIBUTING guidelines.
License
This project is licensed under the MIT License. \ See LICENSE file for details.