@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 +60 -13
- package/index.d.ts +5 -5
- package/index.js +4 -4
- package/index.mjs +4 -4
- package/package.json +1 -1
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
|
|
11
|
-
- **Option #3 -
|
|
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 `
|
|
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-
|
|
189
|
+
#### Option #3 - `protect-granular`
|
|
167
190
|
|
|
168
|
-
This mode is similar to option #2, but it uses `@auth` SDL directive
|
|
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-
|
|
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 `
|
|
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
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
32
|
-
const
|
|
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[
|
|
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 ===
|
|
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-
|
|
28
|
-
const
|
|
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[
|
|
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 ===
|
|
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 {
|