Lighthouse: @can on field level has no $context->user()

Created on 4 Aug 2019  路  7Comments  路  Source: nuwave/lighthouse

I have the below schema

extend type Query @middleware(checks: ["api", "auth:api"]) {
    users: [User!]! @paginate(type: "paginator" model: "App\\Models\\User")
    user(id: ID @eq): User @find(model: "App\\Models\\User")
}

type User {
    id: ID!
    name: String!
    email: String! @can(ability: "viewEmail", model: "App\\Models\\User")
    createdAt: DateTime! @rename(attribute: "created_at")
    updatedAt: DateTime @rename(attribute: "updated_at")
}

I would expect that the middleware is first triggerd and I would be logged in first based on the middleware. However the @can is triggered first. This means, that I don't have the authenticated user and that this will always throw an 403.

I would expect that it works the other way around.

The more general question: How is it possible to block a specific field inside for a type based on someones permissions? For example: an employee can view all users but not their email adres, only their name. Admins can view all data.

Lighthouse Version: 3.7.0
Laravel Version: 5.7

bug

Most helpful comment

I understand the problem you are describing. I think that @middleware is fundamentally flawed in a few ways and we can look for alternative solutions, see https://github.com/nuwave/lighthouse/issues/880

All 7 comments

I agree with your expectation. Can you provide a PR with a failing test case so we can work on fixing this issue?

I ran into a similar problem just now, and I suspect it is caused by the same implementation detail. I would propose the broader formulation for this issue as follows:

Individual field / mutation middleware is executed before the parent query / mutation middleware is executed, resulting in unexpected behavior.

Example:

# This doesn't work as expected (the "admin" middleware won't have access to the 
# currently logged in user, because it is executed before the "auth:api" middleware 
# at the group level)
type Mutation @group(middleware: ["auth:api"]) {
    addPost(id: ID!, contents: String): Post @create
    deleteUser(id: ID!): Record @delete @middleware(checks: ["admin"])
}

# This works, but of course we wouldn't want to apply "admin" middleware to the 
# addPost mutation
type Mutation @group(middleware: ["auth:api", "admin"]) {
    addPost(id: ID!, contents: String): Post @create
    deleteUser(id: ID!): Record @delete
}

# A workaround would be to explicitly add the "auth:api" before the "admin" 
# middleware, but this seems somewhat counterintuitive.
type Mutation @group(middleware: ["auth:api"]) {
    addPost(id: ID!, contents: String): Post @create
    deleteUser(id: ID!): Record @delete @middleware(checks: ["auth:api", "admin"])
}

I will try to provide a PR with a failing test soon.

@sgtlambda @group is removed in v4, can you try upgrading first?

Upgrading to v4, and replacing @group(middleware: [ .. ]) with @middleware(checks: [ .. ]), the problem persists. Updated examples as follows:

# This doesn't work as expected (the "admin" middleware won't have access to the 
# currently logged in user, because it is executed before the "auth:api" middleware 
# at the group level)
type Mutation @middleware(checks: ["auth:api"]) {
    addPost(id: ID!, contents: String): Post @create
    deleteUser(id: ID!): Record @delete @middleware(checks: ["admin"])
}

# This works, but of course we wouldn't want to apply "admin" middleware to the 
# addPost mutation
type Mutation @middleware(checks: ["auth:api", "admin"]) {
    addPost(id: ID!, contents: String): Post @create
    deleteUser(id: ID!): Record @delete
}

# A workaround would be to explicitly add the "auth:api" before the "admin" 
# middleware, but this seems somewhat counterintuitive.
type Mutation @middleware(checks: ["auth:api"]) {
    addPost(id: ID!, contents: String): Post @create
    deleteUser(id: ID!): Record @delete @middleware(checks: ["auth:api", "admin"])
}

I understand the problem you are describing. I think that @middleware is fundamentally flawed in a few ways and we can look for alternative solutions, see https://github.com/nuwave/lighthouse/issues/880

Thank you @sgtlambda for doing my work馃槄. Was a little too bussy at home and missed the notifications. Great to hear this progress

@middleware is deprecated in v5. If you want to have the authenticated user available in the context, use a global middleware.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nguyentrongbang picture nguyentrongbang  路  3Comments

m1guelpf picture m1guelpf  路  3Comments

vine1993 picture vine1993  路  3Comments

spawnia picture spawnia  路  4Comments

eriktisme picture eriktisme  路  4Comments