@envelop/generic-auth 4.0.0-alpha-bed7c7d.0 → 4.0.0-alpha-ab1dc7c.0

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
@@ -6,9 +6,9 @@ This plugin allows you to implement custom authentication flow by providing a cu
6
6
 
7
7
  There are several possible flows for using this plugin (see below for setup examples):
8
8
 
9
- - **Option #1 - Complete Protection**: protected the entire GraphQL schema from unauthenticated access.
10
- - **Option #2 - Manual Validation**: the plugin will just resolve the user and injects it into the `context` without validating the user.
11
- - **Option #3 - Automatic validation using GraphQL directives**: Look for `@auth` directive and automatically protect specific GraphQL fields.
9
+ - **Option #1 - Complete Protection**: protected the entire GraphQL schema from unauthenticated access. Allow unauthenticated access for certain fields by annotating them with a `@skipAuth` directive or `skipAuth` field extension.
10
+ - **Option #2 - Manual Validation**: the plugin will just resolve the user and injects it into the `context` without validating access to schema field.
11
+ - **Option #3 - Granular field access by using schema field directives or field extensions**: Look for an `@auth` directive or `auth` extension field and automatically protect those specific GraphQL fields.
12
12
 
13
13
  ## Getting Started
14
14
 
@@ -102,6 +102,8 @@ const getEnveloped = envelop({
102
102
  });
103
103
  ```
104
104
 
105
+ ##### Allow unauthenticated access for specific fields using a field `directive`
106
+
105
107
  > By default, we assume that you have the GraphQL directive definition as part of your GraphQL schema (`directive @skipAuth on FIELD_DEFINITION`).
106
108
 
107
109
  Then, in your GraphQL schema SDL, you can add `@skipAuth` directive to your fields, and the `validateUser` will not get called while resolving that specific field:
@@ -116,7 +118,28 @@ type Query {
116
118
 
117
119
  > You can apply that directive to any GraphQL `field` definition, not only to root fields.
118
120
 
119
- > If you are using a different directive for authentication, you can pass `authDirectiveName` configuration to customize it.
121
+ > If you are using a different directive for authentication, you can pass `directiveOrExtensionFieldName` configuration to customize it.
122
+
123
+ ##### Allow unauthenticated access for specific fields using a field extension
124
+
125
+ ```typescript
126
+ import { GraphQLObjectType, GraphQLInt } from 'graphql';
127
+
128
+ const GraphQLQueryType = new GraphQLObjectType({
129
+ name: 'Query',
130
+ fields: {
131
+ foo: {
132
+ type: GraphQLInt,
133
+ resolve: () => 1,
134
+ extensions: {
135
+ skipAuth: true,
136
+ },
137
+ },
138
+ },
139
+ });
140
+ ```
141
+
142
+ > If you want to use a different directive for authentication, you can use the `directiveOrExtensionFieldName` configuration to customize it.
120
143
 
121
144
  #### Option #2 - `resolve-only`
122
145
 
@@ -163,9 +186,9 @@ const resolvers = {
163
186
  };
164
187
  ```
165
188
 
166
- #### Option #3 - `protect-auth-directive`
189
+ #### Option #3 - `protect-granular`
167
190
 
168
- This mode is similar to option #2, but it uses `@auth` SDL directive to automatically protect specific GraphQL fields.
191
+ This mode is similar to option #2, but it uses the `@auth` SDL directive or `auth` field extension for protecting specific GraphQL fields.
169
192
 
170
193
  ```ts
171
194
  import { envelop } from '@envelop/core';
@@ -187,12 +210,14 @@ const getEnveloped = envelop({
187
210
  useGenericAuth({
188
211
  resolveUserFn,
189
212
  validateUser,
190
- mode: 'protect-auth-directive',
213
+ mode: 'protect-granular',
191
214
  }),
192
215
  ],
193
216
  });
194
217
  ```
195
218
 
219
+ ##### Protect a field using a field `directive`
220
+
196
221
  > By default, we assume that you have the GraphQL directive definition as part of your GraphQL schema (`directive @auth on FIELD_DEFINITION`).
197
222
 
198
223
  Then, in your GraphQL schema SDL, you can add `@auth` directive to your fields, and the `validateUser` will get called only while resolving that specific field:
@@ -207,21 +232,43 @@ type Query {
207
232
 
208
233
  > You can apply that directive to any GraphQL `field` definition, not only to root fields.
209
234
 
210
- > If you are using a different directive for authentication, you can pass `authDirectiveName` configuration to customize it.
235
+ > If you are using a different directive for authentication, you can pass `directiveOrExtensionFieldName` configuration to customize it.
236
+
237
+ ##### Protect a field using a field extension
238
+
239
+ ```typescript
240
+ import { GraphQLObjectType, GraphQLInt } from 'graphql';
241
+
242
+ const GraphQLQueryType = new GraphQLObjectType({
243
+ name: 'Query',
244
+ fields: {
245
+ foo: {
246
+ type: GraphQLInt,
247
+ resolve: () => 1,
248
+ extensions: {
249
+ auth: true,
250
+ },
251
+ },
252
+ },
253
+ });
254
+ ```
255
+
256
+ > If you are using a different field extension for authentication, you can pass `directiveOrExtensionFieldName` configuration to customize it.
211
257
 
212
258
  ##### Extend authentication with custom directive logic
213
259
 
214
- You can also specify a custom `validateUser` function and get access to the `GraphQLResolveInfo` object while using the `protect-auth-directive` mode:
260
+ You can also specify a custom `validateUser` function and get access to a handy object while using the `protect-all` and `protect-granular` mode:
215
261
 
216
262
  ```ts
263
+ import { GraphQLError } from 'graphql';
217
264
  import { ValidateUserFn } from '@envelop/generic-auth';
218
265
 
219
- const validateUser: ValidateUserFn<UserType> = async (user, context, { root, args, context, info }) => {
266
+ const validateUser: ValidateUserFn<UserType> = async ({ user }) => {
220
267
  // Now you can use the 3rd parameter to implement custom logic for user validation, with access
221
268
  // to the resolver data and information.
222
269
 
223
270
  if (!user) {
224
- throw new Error(`Unauthenticated!`);
271
+ return new GraphQLError(`Unauthenticated.`);
225
272
  }
226
273
  };
227
274
  ```
@@ -242,7 +289,7 @@ Then, you use the `directiveNode` parameter to check the arguments:
242
289
  ```ts
243
290
  import { ValidateUserFn } from '@envelop/generic-auth';
244
291
 
245
- const validateUser: ValidateUserFn<UserType> = async (user, context, { root, args, context, info }, directiveNode) => {
292
+ const validateUser: ValidateUserFn<UserType> = async ({ user, fieldAuthDirectiveNode }) => {
246
293
  // Now you can use the 3rd parameter to implement custom logic for user validation, with access
247
294
  // to the resolver data and information.
248
295
 
@@ -250,7 +297,7 @@ const validateUser: ValidateUserFn<UserType> = async (user, context, { root, arg
250
297
  throw new Error(`Unauthenticated!`);
251
298
  }
252
299
 
253
- const valueNode = directiveNode.arguments.find(arg => arg.name.value === 'role').value as EnumValueNode;
300
+ const valueNode = fieldAuthDirectiveNode.arguments.find(arg => arg.name.value === 'role').value as EnumValueNode;
254
301
  const role = valueNode.value;
255
302
 
256
303
  if (role !== user.role) {
package/index.d.ts CHANGED
@@ -39,10 +39,10 @@ export declare type GenericAuthPluginOptions<UserType extends {} = {}, ContextTy
39
39
  */
40
40
  mode: 'protect-all';
41
41
  /**
42
- * Overrides the default directive name
42
+ * Overrides the default directive name or extension field for marking a field available for unauthorized users.
43
43
  * @default skipAuth
44
44
  */
45
- authDirectiveName?: 'skipAuth' | string;
45
+ directiveOrExtensionFieldName?: 'skipAuth' | string;
46
46
  /**
47
47
  * Customize how the user is validated. E.g. apply authorization role based validation.
48
48
  * The validation is applied during the extended validation phase.
@@ -60,12 +60,12 @@ export declare type GenericAuthPluginOptions<UserType extends {} = {}, ContextTy
60
60
  * resolves the user and inject to authenticated user into the `context`.
61
61
  * And checks for `@auth` directives usages to run validation automatically.
62
62
  */
63
- mode: 'protect-single';
63
+ mode: 'protect-granular';
64
64
  /**
65
- * Overrides the default directive name
65
+ * Overrides the default directive name or extension field for marking a field available only for authorized users.
66
66
  * @default auth
67
67
  */
68
- authDirectiveName?: 'auth' | string;
68
+ directiveOrExtensionFieldName?: 'auth' | string;
69
69
  /**
70
70
  * Customize how the user is validated. E.g. apply authorization role based validation.
71
71
  * The validation is applied during the extended validation phase.
package/index.js CHANGED
@@ -28,14 +28,14 @@ function defaultProtectSingleValidateFn(params) {
28
28
  const useGenericAuth = (options) => {
29
29
  var _a, _b;
30
30
  const contextFieldName = options.contextFieldName || 'currentUser';
31
- if (options.mode === 'protect-all' || options.mode === 'protect-single') {
32
- const directiveName = (_a = options.authDirectiveName) !== null && _a !== void 0 ? _a : (options.mode === 'protect-all' ? 'skipAuth' : 'auth');
31
+ if (options.mode === 'protect-all' || options.mode === 'protect-granular') {
32
+ const directiveOrExtensionFieldName = (_a = options.directiveOrExtensionFieldName) !== null && _a !== void 0 ? _a : (options.mode === 'protect-all' ? 'skipAuth' : 'auth');
33
33
  const validateUser = (_b = options.validateUser) !== null && _b !== void 0 ? _b : (options.mode === 'protect-all' ? defaultProtectAllValidateFn : defaultProtectSingleValidateFn);
34
34
  const extractAuthMeta = (input) => {
35
35
  var _a, _b, _c;
36
36
  return {
37
- fieldAuthExtension: (_a = input.extensions) === null || _a === void 0 ? void 0 : _a[directiveName],
38
- fieldAuthDirectiveNode: (_c = (_b = input.astNode) === null || _b === void 0 ? void 0 : _b.directives) === null || _c === void 0 ? void 0 : _c.find(directive => directive.name.value === directiveName),
37
+ fieldAuthExtension: (_a = input.extensions) === null || _a === void 0 ? void 0 : _a[directiveOrExtensionFieldName],
38
+ fieldAuthDirectiveNode: (_c = (_b = input.astNode) === null || _b === void 0 ? void 0 : _b.directives) === null || _c === void 0 ? void 0 : _c.find(directive => directive.name.value === directiveOrExtensionFieldName),
39
39
  };
40
40
  };
41
41
  return {
package/index.mjs CHANGED
@@ -24,14 +24,14 @@ function defaultProtectSingleValidateFn(params) {
24
24
  const useGenericAuth = (options) => {
25
25
  var _a, _b;
26
26
  const contextFieldName = options.contextFieldName || 'currentUser';
27
- if (options.mode === 'protect-all' || options.mode === 'protect-single') {
28
- const directiveName = (_a = options.authDirectiveName) !== null && _a !== void 0 ? _a : (options.mode === 'protect-all' ? 'skipAuth' : 'auth');
27
+ if (options.mode === 'protect-all' || options.mode === 'protect-granular') {
28
+ const directiveOrExtensionFieldName = (_a = options.directiveOrExtensionFieldName) !== null && _a !== void 0 ? _a : (options.mode === 'protect-all' ? 'skipAuth' : 'auth');
29
29
  const validateUser = (_b = options.validateUser) !== null && _b !== void 0 ? _b : (options.mode === 'protect-all' ? defaultProtectAllValidateFn : defaultProtectSingleValidateFn);
30
30
  const extractAuthMeta = (input) => {
31
31
  var _a, _b, _c;
32
32
  return {
33
- fieldAuthExtension: (_a = input.extensions) === null || _a === void 0 ? void 0 : _a[directiveName],
34
- fieldAuthDirectiveNode: (_c = (_b = input.astNode) === null || _b === void 0 ? void 0 : _b.directives) === null || _c === void 0 ? void 0 : _c.find(directive => directive.name.value === directiveName),
33
+ fieldAuthExtension: (_a = input.extensions) === null || _a === void 0 ? void 0 : _a[directiveOrExtensionFieldName],
34
+ fieldAuthDirectiveNode: (_c = (_b = input.astNode) === null || _b === void 0 ? void 0 : _b.directives) === null || _c === void 0 ? void 0 : _c.find(directive => directive.name.value === directiveOrExtensionFieldName),
35
35
  };
36
36
  };
37
37
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envelop/generic-auth",
3
- "version": "4.0.0-alpha-bed7c7d.0",
3
+ "version": "4.0.0-alpha-ab1dc7c.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "@envelop/core": "^2.0.0",