GraphQL Auth with Passport and Lighthouse PHP

Jose Luis Fonseca on August 02, 2019

Writing a GraphQL API with Lighthouse PHP and Laravel is really fun, but something that you always have to do is add authentication. This is a comm... [Read Full]
markdown guide
 

Hola, a la hora de ejecutar composer require joselfonseca/lighthouse-graphql-passport-auth veo una incompatibilidad con laravel 6, hay planes para actualizar el paquete para laravel 6? te agradesco.

 

Si funciona en laravel 6, pero debes instalar passport 7.5.1 o inferior, así lo deje yo de momento y gracias Jose Luis, excelente aporte :)

"require": {
"php": "7.2",
"fideloper/proxy": "4.0",
"joselfonseca/lighthouse-graphql-passport-auth": "2.0",
"laravel/framework": "6.2",
"laravel/passport": "7.5.1",
"laravel/tinker": "1.0",
"nuwave/lighthouse": "4.5"
},

 
 

Hola, podrías por favor crear el issue en el repo con el error para mirarlo, gracias!

 

Hola, listo, ya abri un nuevo issue con el error. Muchas gracias.

Hola, el problema era que tenias Passport 8 y ese aun no lo teníamos en las dependencias,

github.com/joselfonseca/lighthouse...

Intenta con ese release que ya debe funcionar

 

Hola Jose Luis, Antes que nada quiero agradecer el excelente trabajo que hiciste con Passport y LightHouse.

Te cuento, desde hace un par de días he tenido problemas al instalar Lighthouse GraphQL Passport Auth; Todo funciona de maravilla con Playground, hasta que instalo Lighthouse GraphQL Passport Auth y es entonces cuando Playground me arroja error. Anteriormente ya había usado la libreria sin problemas, no se que esta pasando hago el mismo proceso de implementación.

Agradeceria me comentes si hay algún problema.

Gracias por tu ayuda

Saludos desde La Ciudad de México

"joselfonseca/lighthouse-graphql-passport-auth": "1.4",
"laravel/framework": "5.8.*",
"laravel/passport": "7.4",
"mll-lab/laravel-graphql-playground": "1.1",
"nuwave/lighthouse": "4.1"

thepracticaldev.s3.amazonaws.com/i...

thepracticaldev.s3.amazonaws.com/i...

 

Hola, normalmente eso pasa cuando no hay un mutation en el schema, el trata de extender Mutation pero si no hay por lo menos un Mutation en el schema no hay nada que extender y puede salir ese error. Hay un artículo sobre eso acá mismo en mi blog. Saludos!

 

Efectivamente era eso.

Te agradezco mucho tu ayuda y tu pronta respuesta

Saludos

 

Jose, como podría implementar roles y permisos siguiendo el ejemplo que acabas de hacer,esta genial crack

 

Hola, Yo uso Spatie Permissions, hay un middleware que se puede aplicar para chequear el permiso al query o mutation. es solo usar la directive de middleware. lighthouse-php.com/3.7/api-referen... github.com/spatie/laravel-permission

 

Mucha gracias Jose, yo podría implementar laravel passport con OpenId Connect segun entiendo es mas seguro ya que me genera un id_Token y usando openID Connect puedo enviar permisos directamente en el token. no se que tan necesario sea.
una ultima pregunta, en donde me recomenda almacenar este token, el cliente que consume esta desarrollado con React y Redux.

Bueno lo que pasa en que Passport usa oAuth2, nosotros aca estamos usando eso mismo, OpenID seria otra implementación de auth distinta por ende Passport ya no seria una opción. Creo que los 2 son cosas distintas. Si lo que quieres es usar un Auth server que implemente OpenID seria otra cosa. Ahora si quieres pasar los permisos directos al front puedes incluirlo como parte del user type. YA en el cliente Redux puede guardarlo en el store. No estoy seguro por que dices que el id_Token es mas seguro, de pronto una referencia o documentación me ayudaría para entender el razonamiento por que para los 2 son igual de seguros solo que son implementaciones distintas, con Passport implementas oAuth2 (en una forma GraphQL) y con open id ellos tienen su propio protocolo y especificación si no estoy mal.

En resumen, si lo que quieres es pasar los permisos al Front puedes agregarlos al user type

type User {
    id: ID!
    name: String!
    email: String!
    roles: [Role]
    permissions: [Permission]
}

type Role {
    id: ID!
    name: String!
    permissions: [Permission]
}

type Permission {
    id: ID!
    name: String!
}

El middleware que se le aplique al query y al mutation es quien verifica si tiene o no el permiso para realizar la acción, pasando los permisos al front puedes controlar que el UI muestre o no cosas pero la validación del back es un si o si XD

Lo del Id_token era simplemente algo que escuche en un video por eso te preguntaba, ya que no sabia que eran implementaciones diferentes solo pense que se complementaban una con la otra.
listo jose muchas gracias entonces los permisos los incluyo en el user type pero de toda formas tengo que implementar el middleware en mutations y query

Si claro, La validacion en el back es Obligatoria com Mayusculas hahahaha. Espero haber ayudado. Saludos!

Jose Luis cada vez estoy mas interesado en el trabajo con graphql. A medida que avanzo aparecen nuevas inquietudes y ahora estoy revisando como hacer para que un solo middleware de autorizacion cubra todas las queries y mutations en lugar de indicarlo uno por uno

Hola, Pues middleware global se puede acá github.com/nuwave/lighthouse/blob/... pero hay que tener cuidado por que igual si necesita queries o mutations que no deba aplicar ese middleware ahi ya no le sirve esta solución.

Hola Jose, estoy trabajando el los middleware para toda la cuestion de cords, roles, autenticacion pero no entiendo muy bien como se implementa, por ejemplo tengo dentro de query:

projects: [Project!]! @all(model: "App\Project") @middleware(checks:["auth:api"])

Pero no entiendo de donde sale que va "auth:api", como seria para poner lo de roles , cords entre otros.
talvez si sabes alguna referencia o documentacion para poder entender bien esa cuestion de middleware con graphQl.
Muchas gracias, saludos.

Hola,

Los globales se pueden poner en

github.com/laravel/laravel/blob/ma...

Y los que se aplican a cada tipo se puede poner en el schema definition

lighthouse-php.com/3.7/api-referen...

Saludos

 

hola soy nuevo en laravel y me ocurre un problema todo el tutorial me corre bien pero al momento de modificar en "schema.graphql" no me actualiza las query y mutaciones para realizar pruebas con los cambios que realize
esta es las versiones que instale
"require": {
"php": "7.1.3",
"fideloper/proxy": "4.0",
"joselfonseca/lighthouse-graphql-passport-auth": "2.0",
"laravel/framework": "5.8.*",
"laravel/passport": "7.4",
"laravel/tinker": "1.0",
"mll-lab/laravel-graphql-playground": "1.1",
"nuwave/lighthouse": "4.3"
},
no se si me podrian decir que estoy haciendo mal

 

Hola, puede ser un problema de cache, ahora por defecto Lighthouse guarda el schema en cache.

php artisan cache:clear

Saludos!

 
 

Hi,

Have you had a chance to test a login process? I am having issues with the Passport, GraphQL and PHPUnit test. Think the initial issue was that I did not have a client login and secret in my .env file. I added a DB::table('oauth_clients')->insert at the start of the test, but it did not work. Getting "The user credentials were incorrect." (And I don't really want to be adding the DB::table('oauth_clients')->insert each time to get the user token.

Any help would be appreciated.

** UPDATE **

Ok, I have got it working.

I have called a private function for the DB::insert.

 

This code above doesn't work for me.
I change "data:" to "input:" and works...
If someone have the same problem, just replace "data:" to "input:" and it will working fine.

Thanks for this package, @joselfonseca . ;)

mutation {
login(data: {
username: "myemail@email.com",
password: "123456789qq"
}) {
access_token
refresh_token
expires_in
token_type
user {
id
email
name
created_at
updated_at
}
}
}

 

Hello, I just released version 2.0 which uses input instead of data, thanks for pointing this out in the post, i have updated it.

github.com/joselfonseca/lighthouse...

i've also added registration routes

 

Buenas Jose Luis he segudo tu excelente turorial pero no se por que me sucede esto tengo la version 5.8 de laravel

por insomnia me he autenticado con passport ya sin problemas he realizado peticiones pero al momento de hacerlo con el playground tal como indicas revienta, si puedes ayudarme te lo agradezco Gracias

----CONSULTA----
mutation {
login(input: {
username: "lj.lizarraga@gmail.com",
password: "123456"
}) {
access_token
}
}

------ERROR

{
"errors": [
{
"message": "Client authentication failed",
"extensions": {
"guards": [],
"category": "authentication"
},
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"login"
],
"trace": [
{
"file": "/home/unknown/Escritorio/eqpon/vendor/joselfonseca/lighthouse-graphql-passport-auth/src/GraphQL/Mutations/Login.php",
"line": 21,
"call": "Joselfonseca\LighthouseGraphQLPassport\GraphQL\Mutations\BaseAuthResolver::makeRequest(array(5))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/Schema/Directives/FieldDirective.php",
"line": 71,
"call": "Joselfonseca\LighthouseGraphQLPassport\GraphQL\Mutations\Login::resolve(null, array(3), instance of Nuwave\Lighthouse\Schema\Context, instance of GraphQL\Type\Definition\ResolveInfo)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/Execution/Arguments/SpreadMiddleware.php",
"line": 42,
"call": "Nuwave\Lighthouse\Schema\Directives\FieldDirective::Nuwave\Lighthouse\Schema\Directives\{closure}(null, array(2), instance of Nuwave\Lighthouse\Schema\Context, instance of GraphQL\Type\Definition\ResolveInfo)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/Schema/Factories/FieldFactory.php",
"line": 194,
"call": "Nuwave\Lighthouse\Execution\Arguments\SpreadMiddleware::Nuwave\Lighthouse\Execution\Arguments\{closure}(null, array(1), instance of Nuwave\Lighthouse\Schema\Context, instance of GraphQL\Type\Definition\ResolveInfo)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 632,
"call": "Nuwave\Lighthouse\Schema\Factories\FieldFactory::Nuwave\Lighthouse\Schema\Factories\{closure}(null, array(1), instance of Nuwave\Lighthouse\Schema\Context, instance of GraphQL\Type\Definition\ResolveInfo)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 560,
"call": "GraphQL\Executor\ReferenceExecutor::resolveOrError(instance of GraphQL\Type\Definition\FieldDefinition, instance of GraphQL\Language\AST\FieldNode, instance of Closure, null, instance of Nuwave\Lighthouse\Schema\Context, instance of GraphQL\Type\Definition\ResolveInfo)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 478,
"call": "GraphQL\Executor\ReferenceExecutor::resolveField(GraphQLType: Mutation, null, instance of ArrayObject(1), array(1))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 921,
"call": "GraphQL\Executor\ReferenceExecutor::GraphQL\Executor\{closure}(array(0), 'login')"
},
{
"call": "GraphQL\Executor\ReferenceExecutor::GraphQL\Executor\{closure}(array(0), 'login')"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 923,
"function": "array_reduce(array(1), instance of Closure, array(0))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 494,
"call": "GraphQL\Executor\ReferenceExecutor::promiseReduce(array(1), instance of Closure, array(0))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 256,
"call": "GraphQL\Executor\ReferenceExecutor::executeFieldsSerially(GraphQLType: Mutation, null, array(0), instance of ArrayObject(1))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
"line": 208,
"call": "GraphQL\Executor\ReferenceExecutor::executeOperation(instance of GraphQL\Language\AST\OperationDefinitionNode, null)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/Executor/Executor.php",
"line": 155,
"call": "GraphQL\Executor\ReferenceExecutor::doExecute()"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/GraphQL.php",
"line": 165,
"call": "GraphQL\Executor\Executor::promiseToExecute(instance of GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter, instance of GraphQL\Type\Schema, instance of GraphQL\Language\AST\DocumentNode, null, instance of Nuwave\Lighthouse\Schema\Context, array(0), null, null)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/webonyx/graphql-php/src/GraphQL.php",
"line": 98,
"call": "GraphQL\GraphQL::promiseToExecute(instance of GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter, instance of GraphQL\Type\Schema, 'mutation {\n login(input: {username: \"lj.lizarraga@gmail.com\", password: \"123456\"}) {\n access_token\n }\n}', null, instance of Nuwave\Lighthouse\Schema\Context, array(0), null, null, array(29))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/GraphQL.php",
"line": 170,
"call": "GraphQL\GraphQL::executeQuery(instance of GraphQL\Type\Schema, 'mutation {\n login(input: {username: \"lj.lizarraga@gmail.com\", password: \"123456\"}) {\n access_token\n }\n}', null, instance of Nuwave\Lighthouse\Schema\Context, array(0), null, null, array(29))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/GraphQL.php",
"line": 109,
"call": "Nuwave\Lighthouse\GraphQL::executeQuery('mutation {\n login(input: {username: \"lj.lizarraga@gmail.com\", password: \"123456\"}) {\n access_token\n }\n}', instance of Nuwave\Lighthouse\Schema\Context, array(0), null, null)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/Support/Http/Controllers/GraphQLController.php",
"line": 70,
"call": "Nuwave\Lighthouse\GraphQL::executeRequest(instance of Nuwave\Lighthouse\Execution\LighthouseRequest)"
},
{
"call": "Nuwave\Lighthouse\Support\Http\Controllers\GraphQLController::query(instance of Nuwave\Lighthouse\Execution\LighthouseRequest)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Controller.php",
"line": 54,
"function": "call_user_func_array(array(2), array(1))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php",
"line": 45,
"call": "Illuminate\Routing\Controller::callAction('query', array(1))"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 219,
"call": "Illuminate\Routing\ControllerDispatcher::dispatch(instance of Illuminate\Routing\Route, instance of Nuwave\Lighthouse\Support\Http\Controllers\GraphQLController, 'query')"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 176,
"call": "Illuminate\Routing\Route::runController()"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 680,
"call": "Illuminate\Routing\Route::run()"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 130,
"call": "Illuminate\Routing\Router::Illuminate\Routing\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/nuwave/lighthouse/src/Support/Http/Middleware/AcceptJson.php",
"line": 30,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 171,
"call": "Nuwave\Lighthouse\Support\Http\Middleware\AcceptJson::handle(instance of Illuminate\Http\Request, instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 105,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 682,
"call": "Illuminate\Pipeline\Pipeline::then(instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 657,
"call": "Illuminate\Routing\Router::runRouteWithinStack(instance of Illuminate\Routing\Route, instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 623,
"call": "Illuminate\Routing\Router::runRoute(instance of Illuminate\Http\Request, instance of Illuminate\Routing\Route)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 612,
"call": "Illuminate\Routing\Router::dispatchToRoute(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 176,
"call": "Illuminate\Routing\Router::dispatch(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 130,
"call": "Illuminate\Foundation\Http\Kernel::Illuminate\Foundation\Http\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 171,
"call": "Illuminate\Foundation\Http\Middleware\TransformsRequest::handle(instance of Illuminate\Http\Request, instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 171,
"call": "Illuminate\Foundation\Http\Middleware\TransformsRequest::handle(instance of Illuminate\Http\Request, instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php",
"line": 27,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 171,
"call": "Illuminate\Foundation\Http\Middleware\ValidatePostSize::handle(instance of Illuminate\Http\Request, instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php",
"line": 62,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 171,
"call": "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::handle(instance of Illuminate\Http\Request, instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/fideloper/proxy/src/TrustProxies.php",
"line": 57,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 171,
"call": "Fideloper\Proxy\TrustProxies::handle(instance of Illuminate\Http\Request, instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 105,
"call": "Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 151,
"call": "Illuminate\Pipeline\Pipeline::then(instance of Closure)"
},
{
"file": "/home/unknown/Escritorio/eqpon/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 116,
"call": "Illuminate\Foundation\Http\Kernel::sendRequestThroughRouter(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/public/index.php",
"line": 55,
"call": "Illuminate\Foundation\Http\Kernel::handle(instance of Illuminate\Http\Request)"
},
{
"file": "/home/unknown/Escritorio/eqpon/server.php",
"line": 21,
"function": "require_once('/home/unknown/Escritorio/eqpon/public/index.php')"
}
]
}
]
}

code of conduct - report abuse