@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 +82 -4
- package/cjs/index.js +1 -0
- package/esm/index.js +1 -0
- package/package.json +1 -1
- package/typings/index.d.cts +3 -1
- package/typings/index.d.ts +3 -1
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
|
-
|
|
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
|
-
|
|
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
|
|
295
|
-
// to the resolver
|
|
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
package/esm/index.js
CHANGED
package/package.json
CHANGED
package/typings/index.d.cts
CHANGED
|
@@ -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";
|
package/typings/index.d.ts
CHANGED
|
@@ -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";
|