graphql-mesh icon indicating copy to clipboard operation
graphql-mesh copied to clipboard

Support custom jwt claims in postgraphile handler.

Open MarkLyck opened this issue 2 years ago β€’ 2 comments

Is your feature request related to a problem? Please describe.

I was able to get the postgraphile handler working with our CRM without any issues. But I hit a wall when it came to the RLS (row level security) and JWT claims. There does not seem to be any way to change or add claims to postgraphile (even with the postgraphile options when it's run in schema mode).

This is a blocker for us to use an unmodified version of graphql-mesh

Describe the solution you'd like

graphql-mesh should add an optional function or static object to the postgraphile handler options called pgSettings which takes meshContext as the parameter.

I was able to get postgraphile in graphql-mesh working for us, by editing this file: node_modules/@graphql-mesh/postgraphile/index.js

These are the lines I changed to get it to work:

       // This function just parses the jwt token from the Authorization header.
        const parseJwt = (token) => {
            var base64Url = token.split('.')[1];
            var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
            var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
                return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
            }).join(''));

            return JSON.parse(jsonPayload);
        };

       // πŸ‘‡  This function creates a valid pgSettings object with our custom jwt claims
       // (This is the function i would like to pass in .meshrc.yml) to support custom jwt claims
        const getPgSettings = (context) => {
            try {
                const jwtToken = context.headers.authorization.split(' ')[1]
                const decodedToken = parseJwt(jwtToken)
                
                return {
                    'role': `${decodedToken.x_role}`,
                    'request.jwt.claim.allowed_uids': `${decodedToken.allowed_uids}`,
                    'request.jwt.claim.iss': `${decodedToken.iss}`,
                    'request.jwt.claim.sub': `${decodedToken.sub}`
                }
            } catch(err) {
                return {
                    'role': 'api_user',
                }
            }
        }

        return {
            schema,
            executor: ({ document, variables, context: meshContext, rootValue, operationName, extensions }) => postgraphile.withPostGraphileContext({
                pgPool,
                pgSettings: getPgSettings(meshContext), // πŸ‘ˆ  I added this line to pass custom pgSettings to the postgraphile context
                queryDocumentAst: document,
                operationName,
                variables,
            }, pgContext => jitExecutor({
                document,
                variables,
                context: {
                    ...meshContext,
                    ...pgContext,
                },
                rootValue,
                operationName,
                extensions,
            })),
        };

Describe alternatives you've considered When using postgraphile builder for schema usage there it does NOT allow pgSettings to be passed to builder options which is the only one that's possible to edit from graphql-mesh settings right now.

https://www.graphile.org/postgraphile/usage-schema/

Additional context To get this working we either have to fork graphql-mesh or write a hacky script that insets the function in in withPostGraphileContext to add in pgSettings.

Please consider allowing users to add their own settings or overrides here.

MarkLyck avatar May 06 '22 19:05 MarkLyck

An alternative to this would be support & docs to easily implement custom handlers, so I could just copy the postgraphile handler and add my own settings to it for less common settings like jwt claims.

MarkLyck avatar May 07 '22 14:05 MarkLyck

I ended up solving this for myself temporarily by copying the postgraphile handler, and adding my own pgSettings and publishing it as a private npm package.

Not very clean and it already broke once due to other graphql mesh packages I had to rebase on.

But at least there's a workaround for now.

MarkLyck avatar May 12 '22 20:05 MarkLyck