@envelop/generic-auth 4.5.0 → 4.6.0-alpha-20220926041030-32b77a4b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -256,7 +256,7 @@ const GraphQLQueryType = new GraphQLObjectType({
256
256
 
257
257
  > If you are using a different field extension for authentication, you can pass `directiveOrExtensionFieldName` configuration to customize it.
258
258
 
259
- ##### Extend authentication with custom directive logic
259
+ #### Extend authentication with custom logic
260
260
 
261
261
  You can also specify a custom `validateUser` function and get access to a handy object while using the `protect-all` and `protect-granular` mode:
262
262
 
@@ -274,7 +274,9 @@ const validateUser: ValidateUserFn<UserType> = async ({ user }) => {
274
274
  }
275
275
  ```
276
276
 
277
- And it's also possible to add custom parameters to your `@auth` directive. Here's an example for adding role-aware authentication:
277
+ ##### With a custom directive with arguments
278
+
279
+ It is possible to add custom parameters to your `@auth` directive. Here's an example for adding role-aware authentication:
278
280
 
279
281
  ```graphql
280
282
  enum Role {
@@ -291,8 +293,8 @@ Then, you use the `directiveNode` parameter to check the arguments:
291
293
  import { ValidateUserFn } from '@envelop/generic-auth'
292
294
 
293
295
  const validateUser: ValidateUserFn<UserType> = async ({ user, fieldAuthDirectiveNode }) => {
294
- // Now you can use the 3rd parameter to implement custom logic for user validation, with access
295
- // to the resolver data and information.
296
+ // Now you can use the fieldAuthDirectiveNode parameter to implement custom logic for user validation, with access
297
+ // to the resolver auth directive arguments.
296
298
 
297
299
  if (!user) {
298
300
  throw new Error(`Unauthenticated!`)
@@ -306,3 +308,79 @@ const validateUser: ValidateUserFn<UserType> = async ({ user, fieldAuthDirective
306
308
  }
307
309
  }
308
310
  ```
311
+
312
+ ##### With a custom field extensions
313
+
314
+ You can use custom field extension to pass data to your `validateUser` function instead of using a directive.
315
+ Here's an example for adding role-aware authentication:
316
+
317
+ ```ts
318
+ import { ValidateUserFn } from '@envelop/generic-auth'
319
+
320
+ const validateUser: ValidateUserFn<UserType> = async ({ user, fieldAuthExtension }) => {
321
+ // Now you can use the fieldAuthDirectiveNode parameter to implement custom logic for user validation, with access
322
+ // to the resolver auth directive arguments.
323
+
324
+ if (!user) {
325
+ throw new Error(`Unauthenticated!`)
326
+ }
327
+
328
+ const role = fieldAuthExtension.role
329
+
330
+ if (role !== user.role) {
331
+ throw new Error(`No permissions!`)
332
+ }
333
+ }
334
+
335
+ const resolvers = {
336
+ Query: {
337
+ user: {
338
+ me: (_, __, { currentUser }) => currentUser,
339
+ extensions: {
340
+ auth: {
341
+ role: 'USER'
342
+ }
343
+ }
344
+ }
345
+ }
346
+ }
347
+ ```
348
+
349
+ ##### With a custom validation function per field
350
+
351
+ You can also have access to operation variables and context via the `executionArgs` parameter.
352
+ This can be useful in conjunction with the `fieldAuthExtension` parameter to achieve custom per field validation.
353
+
354
+ ```ts
355
+ import { ValidateUserFn } from '@envelop/generic-auth'
356
+
357
+ const validateUser: ValidateUserFn<UserType> = async ({ user, executionArgs, fieldAuthExtension }) => {
358
+ if (!user) {
359
+ throw new Error(`Unauthenticated!`)
360
+ }
361
+
362
+ // You have access to the object define in the resolver tree, allowing to define any custom logic you want.
363
+ const validate = fieldAuthExtension?.validate
364
+ if (validate) {
365
+ await validate({ user, variables: executionArgs.variableValues, context: executionArgs.contextValue })
366
+ }
367
+ }
368
+
369
+ const resolvers = {
370
+ Query: {
371
+ user: {
372
+ resolve: (_, { userId }) => getUser(userId),
373
+ extensions: {
374
+ auth: {
375
+ validate: ({ user, variables, context }) => {
376
+ // We can now have access to the operation and variables to decide if the user can execute the query
377
+ if (user.id !== variables.userId) {
378
+ throw new Error(`Unauthorized`)
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }
386
+ ```
package/cjs/index.js CHANGED
@@ -58,6 +58,7 @@ const useGenericAuth = (options) => {
58
58
  objectType,
59
59
  fieldAuthDirectiveNode,
60
60
  fieldAuthExtension,
61
+ executionArgs: args,
61
62
  });
62
63
  if (error) {
63
64
  context.reportError(error);
package/esm/index.js CHANGED
@@ -52,6 +52,7 @@ export const useGenericAuth = (options) => {
52
52
  objectType,
53
53
  fieldAuthDirectiveNode,
54
54
  fieldAuthExtension,
55
+ executionArgs: args,
55
56
  });
56
57
  if (error) {
57
58
  context.reportError(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envelop/generic-auth",
3
- "version": "4.5.0",
3
+ "version": "4.6.0-alpha-20220926041030-32b77a4b",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "@envelop/core": "^2.6.0",
@@ -1,5 +1,5 @@
1
1
  import { DefaultContext, Maybe, Plugin, PromiseOrValue } from '@envelop/core';
2
- import { DirectiveNode, FieldNode, GraphQLError, GraphQLObjectType } from 'graphql';
2
+ import { DirectiveNode, ExecutionArgs, FieldNode, GraphQLError, GraphQLObjectType } from 'graphql';
3
3
  export declare class UnauthenticatedError extends GraphQLError {
4
4
  }
5
5
  export declare type ResolveUserFn<UserType, ContextType = DefaultContext> = (context: ContextType) => PromiseOrValue<Maybe<UserType>>;
@@ -14,6 +14,8 @@ export declare type ValidateUserFnParams<UserType> = {
14
14
  fieldAuthDirectiveNode: DirectiveNode | undefined;
15
15
  /** The extensions used for authentication (If using an extension based flow). */
16
16
  fieldAuthExtension: unknown | undefined;
17
+ /** The args passed to the execution function (including operation context and variables) **/
18
+ executionArgs: ExecutionArgs;
17
19
  };
18
20
  export declare type ValidateUserFn<UserType> = (params: ValidateUserFnParams<UserType>) => void | UnauthenticatedError;
19
21
  export declare const DIRECTIVE_SDL = "\n directive @auth on FIELD_DEFINITION\n";
@@ -1,5 +1,5 @@
1
1
  import { DefaultContext, Maybe, Plugin, PromiseOrValue } from '@envelop/core';
2
- import { DirectiveNode, FieldNode, GraphQLError, GraphQLObjectType } from 'graphql';
2
+ import { DirectiveNode, ExecutionArgs, FieldNode, GraphQLError, GraphQLObjectType } from 'graphql';
3
3
  export declare class UnauthenticatedError extends GraphQLError {
4
4
  }
5
5
  export declare type ResolveUserFn<UserType, ContextType = DefaultContext> = (context: ContextType) => PromiseOrValue<Maybe<UserType>>;
@@ -14,6 +14,8 @@ export declare type ValidateUserFnParams<UserType> = {
14
14
  fieldAuthDirectiveNode: DirectiveNode | undefined;
15
15
  /** The extensions used for authentication (If using an extension based flow). */
16
16
  fieldAuthExtension: unknown | undefined;
17
+ /** The args passed to the execution function (including operation context and variables) **/
18
+ executionArgs: ExecutionArgs;
17
19
  };
18
20
  export declare type ValidateUserFn<UserType> = (params: ValidateUserFnParams<UserType>) => void | UnauthenticatedError;
19
21
  export declare const DIRECTIVE_SDL = "\n directive @auth on FIELD_DEFINITION\n";