mercurius-js / auth

Mercurius Auth Plugin
MIT License
82 stars 15 forks source link

Is there a way to make schema filtering work with external policy? #126

Open Mike-Van opened 10 months ago

Mike-Van commented 10 months ago

Hi i'm fairly new to Fastify and Mercurius, I'm trying to setup a graphql api project for 1 of my side project. I saw there's a documentation to filter schema for auth policy directive, n it works great, but for my use case i prefer to use the external auth policy, is there a way to make external policy work for schema filtering, as i might need to expose the graphql playground for potential authenticated users. Here's a minimal snippets of my setup:

const schema = await loadSchema('src/schemas/*.graphql', {
        loaders: [new GraphQLFileLoader()],
    });

const options: MercuriusAuthOptions<any, any, MercuriusContext, TPolicy> = {
    mode: 'external',
    authContext(ctx): TAuthContext {
        const { device, location, role, staff, token, venue } = ctx;
        return { device, location, role, staff, token, venue };
    },
    async applyPolicy(policy, _parent, _args, ctx, _info) {
        const isRolesPolicySatisfied = policy.roles?.length
            ? !!(ctx.auth!.role && policy.roles.includes(ctx.auth!.role.type as USER_ROLE))
            : true;
        const isUserRequiredPolicySatisfied = policy.isUserRequired ? !!ctx.auth!.user : true;
        const isVenueRequiredPolicySatisfied = policy.isVenueRequired ? !!ctx.auth!.venue : true;
        const isRoleRequiredPolicySatisfied = policy.isRoleRequired ? !!ctx.auth!.role : true;
        const isLocationRequiredPolicySatisfied = policy.isLocationRequired ? !!ctx.auth!.location : true;
        const isDeviceRequiredPolicySatisfied = policy.isDeviceRequired ? !!ctx.auth!.device : true;

        const areAllConditionsSatisfied =
            isRolesPolicySatisfied &&
            isUserRequiredPolicySatisfied &&
            isVenueRequiredPolicySatisfied &&
            isRoleRequiredPolicySatisfied &&
            isLocationRequiredPolicySatisfied &&
            isDeviceRequiredPolicySatisfied;

        return areAllConditionsSatisfied;
    },
    policy: {
        // TODO: Add more policies
        Query: {
            getCurrentMenu: {
                isVenueRequired: true,
            },
        },
        Mutation: {},
        Subscription: {},
        Location: {
            current_orders: {
                roles: AUTHENTICATED_ROLES,
            },
            venue: {
                roles: AUTHENTICATED_ROLES,
            },
        },
        Menu: {
            posCategories: {
                roles: AUTHENTICATED_ROLES,
            },
        },
        Category: {
            posItems: {
                roles: AUTHENTICATED_ROLES,
            },
        },
        Item: {
            posOptions: {
                roles: AUTHENTICATED_ROLES,
            },
        },
    },
};

type TPolicy = {
    isRoleRequired?: boolean;
    isUserRequired?: boolean;
    isVenueRequired?: boolean;
    isLocationRequired?: boolean;
    isDeviceRequired?: boolean;
    roles?: USER_ROLE[];
};

    await fastify.register(mercurius, {
        schema,
        resolvers,
        loaders,
        ide: true,
        graphiql: true,
        path: '/graphql',
        allowBatchedQueries: true,
        queryDepth: 10,
        jit: 1,
        context: buildContext,
        subscription: {
            emitter,
            context: buildSubscriptionContext,
        },
        validationRules: isRelease ? [NoSchemaIntrospectionCustomRule] : [],
    });

    await fastify.register(mercuriusAuth, options);
mcollina commented 10 months ago

Does it work? Have you for any issues?

Mike-Van commented 10 months ago

So when i tried to add filterSchema it crashed the app, seems like it doesnt work with external policy:

        mode: 'external',
    authContext(ctx): TAuthContext {
        const { device, location, role, staff, token, venue } = ctx;
        return { device, location, role, staff, token, venue };
    },
    filterSchema: true,
jonnydgreen commented 10 months ago

What error are you seeing? Are you seeing something like this? https://github.com/mercurius-js/auth/blob/main/lib/validation.js#L31

Atm, we don't support this, and to be fair this isn't called out in the docs - something we certainly add for sure!

Would you be interested in adding this caveat to the docs and/or potentially adding support for schema filtering with external policy mode?

Bugs5382 commented 9 months ago

@jonnydgreen Let me take this up. I did not think of externalPolicy. 👍