This seems to have started happening out of nowhere, and it happens on alpha 1, 2, 3 and 4.
I've got the following in my schema:
directive @read(roles: [AUTH_ROLE!]!) on FIELD_DEFINITION
type Query {
twilioAccessToken: String!
authenticatedUser: Users!
inBusinessHours: Boolean!
twilioChildCallSid(parentCallSid: String!): String!
highLevelStatses(startDate: String!, endDate: String!): HighLevelStatses! @read(roles: [JILL_MANAGER, JILL_BUSINESS_DEVELOPMENT, JILL_EXECUTIVE])
jillHighLevelStatses(jillId: ID!, startDate: String!, endDate: String!): JillHighLevelStatses! @read(roles: [JILL_MANAGER, JILL_BUSINESS_DEVELOPMENT, JILL_EXECUTIVE])
teamHighLevelStatses(teamId: ID!, startDate: String!, endDate: String!): TeamHighLevelStatses! @read(roles: [JILL_MANAGER, JILL_BUSINESS_DEVELOPMENT, JILL_EXECUTIVE])
callsForJillStats(jillId: ID!, startDate: String!, endDate: String!): [Calls!]! @read(roles: [JILL_MANAGER, JILL_BUSINESS_DEVELOPMENT, JILL_EXECUTIVE])
billingReportCompanyIds(forMonth: String!): [ID!]!
jillAnswerAttemptIds(jillId: ID!, startDate: String!, endDate: String!): [ID!]!
incomingQueueForIntervalIds(startDate: String!, endDate: String!, incomingCallTypes: [INCOMING_CALL_TYPE!]!, podIds: [ID!]!): [ID!]!
}
enum AUTH_ROLE {
ANONYMOUS
NO_ROLE
PRIVATE
ANYONE
AUTHENTICATED
ENTITY_OWNER
JILL
JILL_OUTBOUND
JILL_MANAGER
JILL_BUSINESS_DEVELOPMENT
JILL_EXECUTIVE
COMPANY_EMPLOYEE
COMPANY_OWNER
}
And when I run graphback generate I get Generation failed: TypeError: JSON cannot represent value: JILL_MANAGER. As far as I know, this wasn't happening until I upgraded to alpha 4. But I then downgraded to different alpha versions, and it kept repeating itself.
Yep.. This looks like issue outside graphback but related to graphback dependencies (mainly graphql-compose).
Minimal reproduction:
directive @read(roles: [AUTH_ROLE!]!) on FIELD_DEFINITION
enum AUTH_ROLE {
ANONYMOUS
}
type Query {
highLevelStatses(startDate: String!, endDate: String!): HighLevelStatses! @read(roles: [JILL_MANAGER, JILL_BUSINESS_DEVELOPMENT, JILL_EXECUTIVE])
}
We need to check if we can
Offtopic,.
On the auth side, it is not good design to have auth roles tied to graphql schema. It is much better to keep roles in database tables.
In https://github.com/aerogear/keycloak-connect-graphql we had exactly the same thing - schema driven auth - but it is much more secure and simpler to manage auth rules in the code.
On the auth side, it is not good design to have auth roles tied to graphql schema. It is much better to keep roles in database tables.
Do you have more information on why this is not a good design? I've studied up on declarative permission with GraphQL quite a bit, and this seems like a good solution, but I'm open to understanding more why it might not be ideal.
It is binding instances of the roles into static compile time values of enum.
Usually roles are configured on some server like keycloak or part of the app database.
It is exposing role information to the client etc.
This is how we configure this ourselves - separate role file https://github.com/aerogear/datasync-starter/blob/master/server/src/config/auth.ts
We planning to add ownership type authz soon as well. Generally things like above will work for startup, but none of the business will put their Auth rules into API definitions that can be introspected or leaked.
Also directives are pretty bad to reflect some complex ACL syntax - this really begs to be code not schema
I see, though the developer experience of having declarative permissions in the schema is fantastic. I wonder if there is a way to get the best of both worlds, the permissions defined with the types in the schema, but hidden from the client. I'm not sure why this would be insecure. AWS AppSync even has schema directives for permissions: https://aws.amazon.com/blogs/mobile/using-multiple-authorization-types-with-aws-appsync-graphql-apis/
Looking more into it, seems like AWS is very comfortable with schema directives for permissions: https://docs.amplify.aws/cli/graphql-transformer/directives#auth
Thanks for highlighting this issue @lastmjs!
I tried it out and it appears to be an issue with graphql-compose.
I've create a bug report https://github.com/graphql-compose/graphql-compose/issues/262 with them so hopefully this will be resolved soon!
Fixed in [email protected]
Amazing @nodkz - thank you!
@nodkz thanks for the fix. I've added a test case for this #1844 and it is failing with.
GraphQLError: Argument "roles" has invalid value ["ANONYMOUS"].
This happens when the schema is being printed using the following code
const schemaComposer = new SchemaComposer(schemaOrSDL)
schemaComposer.toSDL({ exclude: ['String', 'ID', 'Boolean', 'Float', 'Int'] })
I've just extended this test suite with toSDL check and all works correctly https://github.com/graphql-compose/graphql-compose/blob/master/src/__tests__/github_issues/262-test.js#L28-L53
Sorry, but I don't have enough free time to figure it out in your repo. @machi1990, Сan you extend test suite with your broken test case? Only after this, I can fix it.
Tnx.
Hi @nodkz thanks for the quick check.
I believe we have the same schema but this was more of missing descriptions / steps to reproduce what I was seeing. I am sorry for that.
This series of steps (taken from your test case), sum the issue up:
const inputSchema = `
directive @auth(permissions: [CrudPermissions]) on OBJECT | FIELD_DEFINITION
""" @model """
type Note {
id: ID!
title: String! @auth(permissions: [CREATE, READ])
}
enum CrudPermissions {
CREATE
READ
UPDATE
DELETE
}
`;
const composer = new SchemaComposer(inputSchema);
const processedSchema = composer.buildSchema();
const printedProcessedSchema = composer.toSDL({
include: ['Note'],
exclude: ['String', 'ID', 'Boolean', 'Float', 'Int'],
omitDescriptions: true,
});
// at later stage
const thisWorks = new SchemaComposer(processedSchema);
const thisDoesNotWork = new SchemaComposer(printedProcessedSchema);
The error is
GraphQLError: Argument "permissions" has invalid value ["CREATE", "READ"]
@machi1990 thanks for test case. It fixed in 7.19.4
The problem was in printing SDL for Enum AST values in directive arguments:
UPD diff:
- title: String! @auth(permissions: ["CREATE", "READ"])
+ title: String! @auth(permissions: [CREATE, READ])
It was quite difficult to find and fix – https://github.com/graphql-compose/graphql-compose/commit/86765ffeaf923e6b6ca7d3e66ef0a0017c2e7d0a
Thank you @nodkz
@machi1990 thanks for test case. It fixed in 7.19.4
The problem was in printing SDL for Enum AST values in directive arguments:
- title: String! @auth(permissions: [CREATE, READ]) + title: String! @auth(permissions: ["CREATE", "READ"])It was quite difficult to find and fix – graphql-compose/graphql-compose@86765ff
Hi @nodkz thank you for the back to back quick fixes. Now my test case #1844 passes too.
@lastmjs we've dropped another 0.16.0-alpha3 which includes a fix for this issue. Mind checking if this release effectively fix the issue for you? Thanks!
Seems to work! Thanks!
Most helpful comment
Fixed in [email protected]