Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@envelop/generic-auth

Package Overview
Dependencies
Maintainers
1
Versions
1325
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@envelop/generic-auth - npm Package Compare versions

Comparing version 0.0.1-alpha-09d8ef4.0 to 0.0.1-alpha-2d195a2.0

30

index.cjs.js

@@ -5,3 +5,3 @@ 'use strict';

function hasDirective(info, name) {
function getDirective(info, name) {
const { parentType, fieldName, schema } = info;

@@ -13,3 +13,3 @@ const schemaType = schema.getType(parentType.name);

const authDirective = directives.find(d => d.name.value === name);
return !!authDirective;
return authDirective || null;
}

@@ -30,6 +30,6 @@

const validateUser = options.validateUser || defaultValidateFn;
if (options.mode === 'authenticate-all') {
if (options.mode === 'protect-all') {
return {
async onContextBuilding({ context, extendContext }) {
const user = await options.extractUserFn(context);
const user = await options.resolveUserFn(context);
await validateUser(user, context);

@@ -42,6 +42,6 @@ extendContext({

}
else if (options.mode === 'just-extract') {
else if (options.mode === 'resolve-only') {
return {
async onContextBuilding({ context, extendContext }) {
const user = await options.extractUserFn(context);
const user = await options.resolveUserFn(context);
extendContext({

@@ -54,6 +54,6 @@ [fieldName]: user,

}
else if (options.mode === 'auth-directive') {
else if (options.mode === 'protect-auth-directive') {
return {
async onContextBuilding({ context, extendContext }) {
const user = await options.extractUserFn(context);
const user = await options.resolveUserFn(context);
extendContext({

@@ -66,6 +66,11 @@ [fieldName]: user,

return {
async onResolverCalled({ context, info }) {
const shouldAuth = hasDirective(info, options.authDirectiveName || 'auth');
if (shouldAuth) {
await context.validateUser(context[fieldName], context, info);
async onResolverCalled({ args, root, context, info }) {
const authDirectiveNode = getDirective(info, options.authDirectiveName || 'auth');
if (authDirectiveNode) {
await context.validateUser(context[fieldName], context, {
info,
context: context,
args,
root,
}, authDirectiveNode);
}

@@ -83,3 +88,4 @@ },

exports.defaultValidateFn = defaultValidateFn;
exports.getDirective = getDirective;
exports.useGenericAuth = useGenericAuth;
//# sourceMappingURL=index.cjs.js.map

24

index.d.ts
import { DefaultContext, Plugin } from '@envelop/types';
import { GraphQLResolveInfo } from 'graphql';
import { DirectiveNode, GraphQLResolveInfo } from 'graphql';
export * from './utils';
export declare class UnauthenticatedError extends Error {
}
export declare type ExtractUserFn<UserType, ContextType = unknown> = (context: ContextType) => null | UserType | Promise<UserType>;
export declare type ValidateUserFn<UserType, ContextType = unknown> = (user: UserType, context: ContextType, info?: GraphQLResolveInfo) => void | Promise<void>;
export declare type ResolveUserFn<UserType, ContextType = unknown> = (context: ContextType) => null | UserType | Promise<UserType | null>;
export declare type ValidateUserFn<UserType, ContextType = unknown> = (user: UserType, context: ContextType, resolverInfo?: {
root: unknown;
args: Record<string, unknown>;
context: ContextType;
info: GraphQLResolveInfo;
}, directiveNode?: DirectiveNode) => void | Promise<void>;
export declare const DIRECTIVE_SDL = "\n directive @auth on FIELD_DEFINITION\n";

@@ -15,3 +21,3 @@ export declare type GenericAuthPluginOptions<UserType, ContextType> = {

*/
extractUserFn: ExtractUserFn<UserType, ContextType>;
resolveUserFn: ResolveUserFn<UserType, ContextType>;
/**

@@ -32,15 +38,15 @@ * Here you can implement any custom to check if the user is valid and have access to the server.

*/
mode: 'authenticate-all';
mode: 'protect-all';
} | {
/**
* Just extracts the user and inject to authenticated user into the `context`.
* Just resolves the user and inject to authenticated user into the `context`.
* User validation needs to be implemented by you, in your resolvers.
*/
mode: 'just-extract';
mode: 'resolve-only';
} | {
/**
* Extracts the user and inject to authenticated user into the `context`.
* resolves the user and inject to authenticated user into the `context`.
* And checks for `@auth` directives usages to run validation automatically.
*/
mode: 'auth-directive';
mode: 'protect-auth-directive';
/**

@@ -47,0 +53,0 @@ * Overrides the default directive name

@@ -1,2 +0,2 @@

function hasDirective(info, name) {
function getDirective(info, name) {
const { parentType, fieldName, schema } = info;

@@ -8,3 +8,3 @@ const schemaType = schema.getType(parentType.name);

const authDirective = directives.find(d => d.name.value === name);
return !!authDirective;
return authDirective || null;
}

@@ -25,6 +25,6 @@

const validateUser = options.validateUser || defaultValidateFn;
if (options.mode === 'authenticate-all') {
if (options.mode === 'protect-all') {
return {
async onContextBuilding({ context, extendContext }) {
const user = await options.extractUserFn(context);
const user = await options.resolveUserFn(context);
await validateUser(user, context);

@@ -37,6 +37,6 @@ extendContext({

}
else if (options.mode === 'just-extract') {
else if (options.mode === 'resolve-only') {
return {
async onContextBuilding({ context, extendContext }) {
const user = await options.extractUserFn(context);
const user = await options.resolveUserFn(context);
extendContext({

@@ -49,6 +49,6 @@ [fieldName]: user,

}
else if (options.mode === 'auth-directive') {
else if (options.mode === 'protect-auth-directive') {
return {
async onContextBuilding({ context, extendContext }) {
const user = await options.extractUserFn(context);
const user = await options.resolveUserFn(context);
extendContext({

@@ -61,6 +61,11 @@ [fieldName]: user,

return {
async onResolverCalled({ context, info }) {
const shouldAuth = hasDirective(info, options.authDirectiveName || 'auth');
if (shouldAuth) {
await context.validateUser(context[fieldName], context, info);
async onResolverCalled({ args, root, context, info }) {
const authDirectiveNode = getDirective(info, options.authDirectiveName || 'auth');
if (authDirectiveNode) {
await context.validateUser(context[fieldName], context, {
info,
context: context,
args,
root,
}, authDirectiveNode);
}

@@ -75,3 +80,3 @@ },

export { DIRECTIVE_SDL, UnauthenticatedError, defaultValidateFn, useGenericAuth };
export { DIRECTIVE_SDL, UnauthenticatedError, defaultValidateFn, getDirective, useGenericAuth };
//# sourceMappingURL=index.esm.js.map
{
"name": "@envelop/generic-auth",
"version": "0.0.1-alpha-09d8ef4.0",
"version": "0.0.1-alpha-2d195a2.0",
"sideEffects": false,

@@ -5,0 +5,0 @@ "peerDependencies": {

## `@envelop/generic-auth`
This plugin allows you to implement custom authentication flow, by providing a custom user extraction based on the original HTTP request. The extracted user is being injected into the GraphQL execution `context` and you can use it in your resolvers to fetch the current user.
This plugin allows you to implement custom authentication flow by providing a custom user resolver based on the original HTTP request. The resolved user is injected into the GraphQL execution `context`, and you can use it in your resolvers to fetch the current user.

@@ -9,5 +9,5 @@ > The plugin also comes with an optional `@auth` directive that can be added to your GraphQL schema and helps you to protect your GraphQL schema in a declarative way.

- **Option #1 - Complete Protection**: to protect your entire GraphQL schema, by validating the user before executing the request.
- **Option #2 - Fine-grain Protection**: Use the plugin to inject to authenticated user into the `context`, and later you can verify it in your resolvers.
- **Option #3 - Fine-grain Protection with Directives**: Uses `@auth` SDL directive to automatically protect specific GraphQL fields.
- **Option #1 - Complete Protection**: protected the entire GraphQL schema from unauthenticated access.
- **Option #2 - Manual Validation**: the plugin will just resolve the user and injects it into the `context` without validating the user.
- **Option #3 - Automatic validation using GraphQL directives**: Look for `@auth` directive and automatically protect specific GraphQL fields.

@@ -24,3 +24,3 @@ ## Getting Started

1. Extract your user from the request by implementing `extractUser`:
1. Resolve your user from the request by implementing `resolveUserFn`:

@@ -30,3 +30,3 @@ Use this method to only extract the user from the context, with any custom code, for example:

```ts
import { ExtractUserFn } from '@envelop/generic-auth';
import { ResolveUserFn } from '@envelop/generic-auth';

@@ -37,3 +37,3 @@ type UserType = {

const extractUserFn: ExtractUserFn<UserType> = async context => {
const resolveUserFn: ResolveUserFn<UserType> = async context => {
// Here you can implement any custom sync/async code, and use the context built so far in Envelop and the HTTP request

@@ -58,3 +58,3 @@ // to find the current user.

This method is optional, by default, it will just check the value returned by `extractUserFn` and throw an error in case of a falsey value.
This method is optional; the default method will just verify the value returned by `resolveUser` and throw an error in case of a false value (`false | null | undefined`).

@@ -68,4 +68,3 @@ ```ts

// If you are using `auth-directive` mode, you'll also get a third parameter for the GraphQLResolveInfo
// of the resolvers being resolved at the moment.
// If you are using the `protect-auth-directive` mode, you'll also get 2 additional parameters: the resolver parameters as object and the DirectiveNode of the auth directive.

@@ -78,7 +77,7 @@ if (!user) {

Now, configure your plugin based on the mode you with to use:
Now, configure your plugin based on the mode you wish to use:
#### Option #1 - `authenticate-all`
#### Option #1 - `protect-all`
This mode offers complete protection for the entire API. It protects your entire GraphQL schema, by validating the user before executing the request.
This mode offers complete protection for the entire API. It protects your entire GraphQL schema by validating the user before executing the request.

@@ -89,3 +88,3 @@ To setup this mode, use the following config:

import { envelop } from '@envelop/core';
import { useGenericAuth, ExtractUserFn, ValidateUserFn } from '@envelop/generic-auth';
import { useGenericAuth, resolveUser, ValidateUserFn } from '@envelop/generic-auth';

@@ -95,3 +94,3 @@ type UserType = {

};
const extractUserFn: ExtractUserFn<UserType> = async context => {
const resolveUserFn: ResolveUserFn<UserType> = async context => {
/* ... */

@@ -107,5 +106,5 @@ };

useGenericAuth({
extractUserFn,
resolveUser,
validateUser,
mode: 'authenticate-all',
mode: 'protect-all',
}),

@@ -116,9 +115,9 @@ ],

#### Option #2 - `just-extract`
#### Option #2 - `resolve-only`
This mode uses the plugin to inject to authenticated user into the `context`, and later you can verify it in your resolvers.
This mode uses the plugin to inject the authenticated user into the `context`, and later you can verify it in your resolvers.
```ts
import { envelop } from '@envelop/core';
import { useGenericAuth, ExtractUserFn, ValidateUserFn } from '@envelop/generic-auth';
import { useGenericAuth, resolveUser, ValidateUserFn } from '@envelop/generic-auth';

@@ -128,3 +127,3 @@ type UserType = {

};
const extractUserFn: ExtractUserFn<UserType> = async context => {
const resolveUserFn: ResolveUserFn<UserType> = async context => {
/* ... */

@@ -140,5 +139,5 @@ };

useGenericAuth({
extractUserFn,
resolveUser,
validateUser,
mode: 'just-extract',
mode: 'resolve-only',
}),

@@ -164,3 +163,3 @@ ],

#### Option #3 - `auth-directive`
#### Option #3 - `protect-auth-directive`

@@ -171,3 +170,3 @@ This mode is similar to option #2, but it uses `@auth` SDL directive to automatically protect specific GraphQL fields.

import { envelop } from '@envelop/core';
import { useGenericAuth, ExtractUserFn, ValidateUserFn } from '@envelop/generic-auth';
import { useGenericAuth, resolveUser, ValidateUserFn } from '@envelop/generic-auth';

@@ -177,3 +176,3 @@ type UserType = {

};
const extractUserFn: ExtractUserFn<UserType> = async context => {
const resolveUserFn: ResolveUserFn<UserType> = async context => {
/* ... */

@@ -189,5 +188,5 @@ };

useGenericAuth({
extractUserFn,
resolveUser,
validateUser,
mode: 'auth-directive',
mode: 'protect-auth-directive',
}),

@@ -198,3 +197,3 @@ ],

> By defualt, we assume that you have the GraphQL directive defition as part of your GraphQL schema (`directive @auth on FIELD_DEFINITION`).
> By default, we assume that you have the GraphQL directive definition as part of your GraphQL schema (`directive @auth on FIELD_DEFINITION`).

@@ -207,3 +206,3 @@ 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:

protectedField: String @auth
publicField: String
# publicField: String
}

@@ -215,1 +214,51 @@ ```

> If you are using a different directive for authentication, you can pass `authDirectiveName` configuration to customize it.
##### Extend authentication with custom directive logic
You can also specify a custom `validateUser` function and get access to the `GraphQLResolveInfo` object while using the `protect-auth-directive` mode:
```ts
import { ValidateUserFn } from '@envelop/generic-auth';
const validateUser: ValidateUserFn<UserType> = async (user, context, { root, args, context, info }) => {
// Now you can use the 3rd parameter to implement custom logic for user validation, with access
// to the resolver data and information.
if (!user) {
throw new Error(`Unauthenticated!`);
}
};
```
And it's also possible to add custom parameters to your `@auth` directive. Here's an example for adding role-aware authentication:
```graphql
enum Role {
ADMIN
MEMBER
}
directive @auth(role: Role!) on FIELD_DEFINITION
```
Then, you use the `directiveNode` parameter to check the arguments:
```ts
import { ValidateUserFn } from '@envelop/generic-auth';
const validateUser: ValidateUserFn<UserType> = async (user, context, { root, args, context, info }, directiveNode) => {
// Now you can use the 3rd parameter to implement custom logic for user validation, with access
// to the resolver data and information.
if (!user) {
throw new Error(`Unauthenticated!`);
}
const valueNode = authDirectiveNode.arguments.find(arg => arg.name.value === 'role').value as EnumValueNode;
const role = valueNode.value;
if (role !== user.role) {
throw new Error(`No permissions!`);
}
};
```

@@ -1,2 +0,2 @@

import { GraphQLResolveInfo } from 'graphql';
export declare function hasDirective(info: GraphQLResolveInfo, name: string): boolean;
import { DirectiveNode, GraphQLResolveInfo } from 'graphql';
export declare function getDirective(info: GraphQLResolveInfo, name: string): null | DirectiveNode;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc