Introducción

Laravel ya facilita la autenticación por medio de formularios de inicio de sesión tradicionales, pero ¿Qué pasa con las APIs? Las APIs típicamente usan tokens para autenticar a los usuarios y no mantienen el estado de sesión entre solicitudes. Laravel hace de la autenticación de API algo muy simple usando Passport de Laravel, el cual proporciona una implementación de servidor OAuth2 completa para tu aplicación Laravel en sólo minutos. Passport está construido sobre el servidor League OAuth2 que es mantenido por Andy Millington y Simon Hamp.

Esta documentación asume que estás familiarizado con OAuth2. Si no sabes nada sobre OAuth2, considera familiarizarte con la terminología general y las características de Outh2 antes de continuar.

Actualizando Passport

Al actualizar a una nueva versión mayor de Passport, es importante que revises detalladamente la guía de actualización.

Instalación

Para empezar, instala Passport por medio del gestor de paquetes Composer:

composer require laravel/passport

El proveedor de servicio de Passport registra su propio directorio de migración de base de datos con el framework, así que deberías migrar tu base de datos después de instalar el paquete. Las migraciones de Passport crearán las tablas que tu aplicación necesita para almacenar clientes y tokens de acceso:

php artisan migrate

A continuación, debes ejecutar el comando passport:install. Este comando creará las claves de encriptación necesarias para generar tokens de acceso seguro. Además, el comando creará clientes de «acceso personal» y «permiso de contraseña» los cuales serán usados para generar tokens de acceso:

php artisan passport:install

Después de ejecutar este comando, agrega el trait Laravel\Passport\HasApiTokens a tu modelo App\User. Este trait proporcionará algunos métodos helper para tu modelo los cuales permitirán que inspecciones el token y alcances del usuario autenticado:

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

Luego, deberías llamar al método Passport::routes dentro del método boot de tu AuthServiceProvider. Este método registrará las rutas necesarias para suministrar tokens y revocar tokens de acceso, clientes y tokens de acceso personal:

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
    * The policy mappings for the application.
    *
    * @var array
    */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
    * Register any authentication / authorization services.
    *
    * @return void
    */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}

Finalmente, en tu archivo de configuración config/auth.php, debes establecer la opción driver del guard de autenticación de api a passport. Esto indicará a tu aplicación que utilice el TokenGuard de Passport al momento de autenticar las solicitudes de API entrantes:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

Personalización de la migración

Si no vas a utilizar las migraciones predeterminadas de Passport, debes llamar al método Passport::ignoreMigrations en el método register de tu AppServiceProvider. Puedes exportar las migraciones por defecto usando php artisan vendor:publish --tag=passport-migrations.

Por defecto, Passport usa una columna de enteros para almacenar el user_id. Si tu aplicación utiliza un tipo de columna diferente para identificar a los usuarios (por ejemplo: UUID), debes modificar las migraciones de Passport predeterminadas después de publicarlas.

Inicio rápido de frontend

Para usar los componentes Vue de Passport, debes estar usando el framework de JavaScript Vue. Estos componentes también usarán el framework de CSS Bootstrap. Sin embargo, incluso si no estás usando estas herramientas, los componentes sirven como una referencia valiosa para tu propia implementación de frontend.

Passport viene con una API JSON que puedes usar para permitir que tus usuarios creen tokens de acceso de clientes y personal. Sin embargo, puede ser que consumas tiempo en codificar un frontend para interactuar con estas APIs. Así que, Passport también incluye componentes de Vue pre-construidos que puedes usar como implementación de ejemplo o punto de inicio para tu propia implementación.

Para publicar los componentes de Vue de Passport, usa el comando Artisan vendor:publish:

php artisan vendor:publish --tag=passport-components

Los componentes publicados serán colocados en tu directorio resources/js/components. Una vez que los componentes han sido publicados, debes registrarlos en tu archivo resources/js/app.js:

Vue.component(
    'passport-clients',
    require('./components/passport/Clients.vue').default
);

Vue.component(
    'passport-authorized-clients',
    require('./components/passport/AuthorizedClients.vue').default
);

Vue.component(
    'passport-personal-access-tokens',
    require('./components/passport/PersonalAccessTokens.vue').default
);

Antes de Laravel v5.7.19, anexar .default al registrar componentes da como resultado un error de consola. Una explicación para este cambio puedes encontrarla en las notas de lanzamiento de Laravel Mix v4.0.0.

Después de registrar los componentes, asegúrate de ejecutar npm run dev para recompilar tu código CSS/JS. Una vez que has recompilado tus código CSS/JS, puedes colocar los componentes dentro de una de las plantillas de tu aplicación para empezar a crear tokens de acceso de clientes y personal:

<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>

Despliegue de passport

Al momento de usar Passport en tus servidores de producción por primera vez, es probable que debas ejecutar el comando passport:keys. Este comando genera las claves de encriptación que Passport necesita con el propósito de generar el token de acceso. Las claves generadas normalmente no son guardadas en control de código fuente:

php artisan passport:keys

De ser necesario, puedes definir la ruta desde donde se deben cargar las claves de Passport. Para lograr esto puedes usar el método Passport::loadKeysFrom:

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    Passport::loadKeysFrom('/secret-keys/oauth');
}

Además, puedes publicar el archivo de configuración de Passport usando php artisan vendor:publish --tag=passport-config, el cual proporcionará la opción de cargar las claves de encriptación desde tus variables de entorno:

PASSPORT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
<private key here>
-----END RSA PRIVATE KEY-----"

PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
<public key here>
-----END PUBLIC KEY-----"

Configuración

Duración de tokens

De forma predeterminada, Passport emite tokens de acceso de larga duración que caducan después de un año. Si prefieres configurar una duración de token más larga o más corta, puedes usar los métodos tokensExpireIn, refreshTokensExpireIn y personalAccessTokensExpireIn. Estos métodos deberían ser llamados desde el método boot de tu AuthServiceProvider:

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    Passport::tokensExpireIn(now()->addDays(15));

    Passport::refreshTokensExpireIn(now()->addDays(30));

    Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}

Sobrescribiendo modelos predeterminados

Eres en libre de extender los modelos usados internamente por Passport:

use Laravel\Passport\Client as PassportClient;

class Client extends PassportClient
{
    // ...
}

A continuación, puedes indicarle a Passport que utilice tus modelos personalizados a través de la clase Passport:

use App\Models\Passport\AuthCode;
use App\Models\Passport\Client;
use App\Models\Passport\PersonalAccessClient;
use App\Models\Passport\Token;

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    Passport::useTokenModel(Token::class);
    Passport::useClientModel(Client::class);
    Passport::useAuthCodeModel(AuthCode::class);
    Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}

Emitiendo tokens de acceso

Usar OAuth2 con códigos de autorización es la forma en que la mayoría de los desarrolladores están familiarizados con OAuth2. Al usar códigos de autorización, una aplicación cliente redireccionará un usuario a tu servidor donde aprobará o denegará la solicitud para emitir un token de acceso al cliente.

Administrando clientes

En primer lugar, los desarrolladores que crean aplicaciones que necesitan interactuar con la API de tu aplicación deberán registrar su aplicación con la tuya creando un «cliente». Normalmente, esto consiste en proporcionar el nombre de su aplicación y una dirección URL a la que tu aplicación puede redirigir después de que los usuarios aprueben su solicitud de autorización.

El comando passport:client

La forma más simple de crear un cliente es usando el comando Artisan passport:client. Este comando puede ser usado para crear tus propios clientes para probar tu funcionalidad OAuth2. Cuando ejecutes el comando client, Passport te pedirá más información sobre tu cliente y te proporcionará un ID y clave secreta de cliente:

php artisan passport:client

Redirigir URLs

Si deseas incluir en la lista blanca varias direcciones URL de redireccionamiento para tu cliente, puedes especificarlas mediante una lista delimitadas por comas cuando se solicite la dirección URL mediante el comando passport:client:

http://example.com/callback,http://examplefoo.com/callback

Cualquier URL que contenga comas debe estar codificada.

API JSON

Debido a que tus usuarios no podrán utilizar el comando client, Passport proporciona una API JSON que puedes usar para crear clientes. Esto te ahorra la molestia de tener que codificar manualmente los controladores para crear, actualizar y eliminar clientes.

Sin embargo, necesitarás acoplar la API JSON de Passport con tu propio frontend para proporcionar un panel de control para que tus usuarios administren sus clientes. A continuación, revisaremos todos los endpoints de API para administrar clientes. Por conveniencia, usaremos Axios para demostrar la forma de hacer las solicitudes HTTP hacia los endpoints.

La API JSON está protegida por los middleware web y auth; por lo tanto, sólo puede ser llamada desde tu propia aplicación. No se puede llamar desde una fuente externa.

Si no quieres implementar todo el frontend de administración de clientes tu mismo, puedes usar el inicio rápido de frontend para tener un frontend completamente funcional en sólo minutos.

GET /oauth/clients

Esta ruta devuelve todos los clientes para el usuario autenticado. Esto es útil principalmente para listar todos los clientes del usuario para que puedan editarlos o eliminarlos:

axios.get('/oauth/clients')
    .then(response => {
        console.log(response.data);
    });

POST /oauth/clients

Esta ruta se utiliza para crear nuevos clientes. Requiere dos datos: el name del cliente y un redirect de la URL. El redirect de la URL es donde el usuario será redirigido después de que sea aprobada o rechazada su solicitud de autorización.

Cuando se crea un cliente, se emitirá un ID de cliente y una clave secreta. Estos valores se usarán cuando se soliciten tokens de acceso desde tu aplicación. La ruta de creación del cliente devolverá la nueva instancia del cliente:

const data = {
    name: 'Client Name',
    redirect: 'http://example.com/callback'
};

axios.post('/oauth/clients', data)
    .then(response => {
        console.log(response.data);
    })
    .catch (response => {
        // List errors on response...
    });

PUT /oauth/clients/{client-id}

Esta ruta se utiliza para actualizar clientes. Requiere dos datos: el name del cliente y un redirect de la URL. El redirect de la URL es donde el usuario será redirigido después de que sea aprobada o rechazada su solicitud de autorización. La ruta devolverá la instancia de cliente actualizada:

const data = {
    name: 'New Client Name',
    redirect: 'http://example.com/callback'
};

axios.put('/oauth/clients/' + clientId, data)
    .then(response => {
        console.log(response.data);
    })
    .catch (response => {
        // List errors on response...
    });

DELETE /oauth/clients/{client-id}

Esta ruta se utiliza para eliminar clientes:

axios.delete('/oauth/clients/' + clientId)
    .then(response => {
        //
    });

Solicitando tokens

Redirección para autorización

Una vez que se ha creado un cliente, los desarrolladores pueden usar el ID de cliente y la clave secreta para solicitar un código de autorización y un token de acceso de la aplicación. En primer lugar, la aplicación consumidora debe realizar una solicitud de redirección a la ruta /oauth/authorize de tu aplicación de la siguiente manera:

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://example.com/callback',
        'response_type' => 'code',
        'scope' => '',
        'state' => $state,
    ]);

    return redirect('http://your-app.com/oauth/authorize?'.$query);
});

Recuerda, la ruta /oauth/authorize ya está definida por el método Passport::routes. No necesitas definir manualmente esta ruta.

Aprobación de la solicitud

Al recibir solicitudes de autorización, Passport mostrará automáticamente una plantilla al usuario que le permite aprobar o rechazar la solicitud de autorización. Si aprueban la solicitud, serán redirigidos de nuevo a la redirect_uri especificada por la aplicación consumidora. La redirect_uri debe coincidir con el redirect de la URL que se especificó cuando se creó el cliente.

Si deseas personalizar la pantalla de aprobación de la autorización, puedes publicar las vistas de Passport usando el comando Artisan vendor:publish. Las vistas publicadas serán colocadas en resources/views/vendor/passport:

php artisan vendor:publish --tag=passport-views

A veces es posible que desees omitir la pantalla de autorización, como cuando autorizas a un cliente propio. Puedes lograr esto extendiendo el modelo Client y definiendo un método skipsAuthorization. Si skipsAuthorization devuelve true el cliente será aprobado y el usuario será redirigido de nuevo a la redirect_uri inmediatamente.

<?php

namespace App\Models\Passport;

use Laravel\Passport\Client as BaseClient;

class Client extends BaseClient
{
    /**
        * Determine if the client should skip the authorization prompt.
        *
        * @return bool
        */
    public function skipsAuthorization()
    {
        return $this->firstParty();
    }
}

Conversión de códigos de autorización a tokens de acceso

Si el usuario aprueba la solicitud de autorización, será redirigido de nuevo a la aplicación consumidora. El consumidor debe verificar primero el parámetro state contra el valor almacenado antes de la redirección. Si el parámetro state coincide, el consumidor debe emitir una solicitud POST a tu aplicación para solicitar un token de acceso. La solicitud debe incluir el código de autorización que fue emitido por tu aplicación cuando el usuario aprobó la solicitud de autorización. En este ejemplo, utilizaremos la librería Guzzle HTTP para hacer la solicitud POST:

Route::get('/callback', function (Request $request) {
    $state = $request->session()->pull('state');

    throw_unless(
        strlen($state) > 0 && $state === $request->state,
        InvalidArgumentException::class
    );

    $http = new GuzzleHttp\Client;

    $response = $http->post('http://your-app.com/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => 'client-id',
            'client_secret' => 'client-secret',
            'redirect_uri' => 'http://example.com/callback',
            'code' => $request->code,
        ],
    ]);

    return json_decode((string) $response->getBody(), true);
});

Esta ruta /oauth/token devolverá una respuesta JSON que contiene los atributos access_token, refresh_token, y expires_in. El atributo expires_in contiene el número de segundos hasta que el token de acceso expire.

Como la ruta /oauth/authorize, la ruta /oauth/token está definida para ti por el método Passport::routes. No necesitas definir manualmente esta ruta. Por defecto, esta ruta es regulada usando la configuración del middleware ThrottleRequests.

Actualización de tokens

Si tu aplicación emite tokens de acceso de corta duración, los usuarios deberán actualizar sus tokens de acceso por medio del token de actualización que se les proporcionó cuando se emitió el token de acceso. En este ejemplo, utilizaremos la librería Guzzle HTTP para actualizar el token:

$http = new GuzzleHttp\Client;

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'refresh_token',
        'refresh_token' => 'the-refresh-token',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => '',
    ],
]);

return json_decode((string) $response->getBody(), true);

Esta ruta /oauth/token devolverá una respuesta JSON que contiene los atributos access_token, refresh_token, y expires_in. El atributo expires_in contiene el número de segundos hasta que el token de acceso expire.

Eliminando tokens

Cuando los tokens han sido revocados o han expirado, es posible que desees eliminarlos de la base de datos. Passport viene con un comando que puede hacer esto por ti:

# Purge revoked and expired tokens and auth codes...
php artisan passport:purge

# Only purge revoked tokens and auth codes...
php artisan passport:purge --revoked 

# Only purge expired tokens and auth codes...
php artisan passport:purge --expired

También puedes configurar un trabajo programado en la clase Kernel de tu consola para eliminar automáticamente los tokens según una programación:

/**
    * Define the application's command schedule.
    *
    * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
    * @return void
    */
protected function schedule(Schedule $schedule)
{
    $schedule->command('passport:purge')->hourly();
}

Otorgando códigos de autorización con PKCE

Otorgar códigos de autorización con «Clave de prueba para el intercambio de código» (Proof Key for Code Exchange o PKCE) es una forma segura de autenticar aplicaciones de una sola página (SPA) o aplicaciones nativas para acceder a tu API. Esta forma de acceso se debe usar cuando no puedas garantizar que la clave secreta del cliente se almacenará de forma confidencial o para mitigar la amenaza de que un atacante intercepte el código de autorización. Una combinación de un «verificador de código» y un «desafío de código» reemplaza la clave secreta del cliente cuando se cambia el código de autorización por un token de acceso.

Creando el cliente

Antes que tu aplicación pueda emitir tokens por medio del código de autorización otorgado con PKCE, necesitarás crear un cliente habilitado para PKCE. Puedes hacer esto usando el comando passport:client con la opción --public:

php artisan passport:client --public

Solicitando tokens

Verificador de código y desafío de código

Como otorgar esta autorización no proporciona una clave secreta al cliente, los desarrolladores necesitarán generar una combinación de un verificador de código y un desafío de código para solicitar un token.

El verificador de código debe ser una cadena aleatoria entre 43 y 128 caracteres que contengan letras, números y "-", ".", "_", "~", como se define en la especificación RFC 7636.

El desafío de código debe ser una cadena codificada en Base64 con URL y caracteres seguros para el nombre de archivo. Los caracteres '=' al final deben ser eliminados y no debe haber saltos de línea, espacios en blanco u otros caracteres adicionales.

$encoded = base64_encode(hash('sha256', $code_verifier, true));

$codeChallenge = strtr(rtrim($encoded, '='), '+/', '-_');

Redirección para autorización

Una vez que se ha creado un cliente, puedes usar el ID del cliente, el verificador de código generado y el desafío de código para solicitar un código de autorización y un token de acceso de tu aplicación. En primer lugar, la aplicación consumidora debe hacer una solicitud de redirección a la ruta /oauth/authorize de tu aplicación:

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $request->session()->put('code_verifier', $code_verifier = Str::random(128));

    $codeChallenge = strtr(rtrim(
        base64_encode(hash('sha256', $code_verifier, true))
    , '='), '+/', '-_');

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://example.com/callback',
        'response_type' => 'code',
        'scope' => '',
        'state' => $state,
        'code_challenge' => $codeChallenge,
        'code_challenge_method' => 'S256',
    ]);

    return redirect('http://your-app.com/oauth/authorize?'.$query);
});

Conversión de códigos de autorización a tokens de acceso

Si el usuario aprueba la solicitud de autorización, será redirigido de nuevo a la aplicación consumidora. El consumidor debe verificar el parámetro state contra el valor almacenado antes de la redirección, como en el otorgamiento de código de autorización estándar.

Si el parámetro state coincide, el consumidor debe emitir una solicitud POST a tu aplicación para solicitar un token de acceso. La solicitud debe incluir el código de autorización que fue emitido por tu aplicación cuando el usuario aprobó la solicitud de autorización junto con el verificador de código generado originalmente:

Route::get('/callback', function (Request $request) {
    $state = $request->session()->pull('state');

    $codeVerifier = $request->session()->pull('code_verifier');

    throw_unless(
        strlen($state) > 0 && $state === $request->state,
        InvalidArgumentException::class
    );

    $response = (new GuzzleHttp\Client)->post('http://your-app.com/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => 'client-id',
            'redirect_uri' => 'http://example.com/callback',
            'code_verifier' => $codeVerifier,
            'code' => $request->code,
        ],
    ]);

    return json_decode((string) $response->getBody(), true);
});

Tokens de permiso de contraseña

Otorgar contraseña de OAuth2 permite a tus otros clientes externos, como una aplicación móvil, obtener un token de acceso usando una dirección de correo electrónico / nombre de usuario y una contraseña. Esto te permite emitir tokens de acceso de forma segura a tus clientes externos sin necesidad de que tus usuarios pasen por todo el flujo de redirección del código de autorización de OAuth2.

Creando un cliente con permiso de contraseña

Antes que tu aplicación pueda emitir tokens por medio de permiso de contraseña, necesitarás crear un cliente con permiso de contraseña. Puedes hacer esto usando el comando passport:client con la opción --password. Si ya has ejecutado el comando passport:install, no necesitas ejecutar este comando:

php artisan passport:client --password

Solicitando tokens

Una vez que se ha creado un cliente con permiso de contraseña, puedes solicitar un token de acceso emitiendo una solicitud POST a la ruta /oauth/token con la dirección de correo electrónico y la contraseña del usuario. Recuerda, esta ruta ya está registrada por el método Passport::routes por lo que no es necesario definirla manualmente. Si la solicitud es exitosa, recibirás un access_token y un refresh_token en la respuesta JSON del servidor:

$http = new GuzzleHttp\Client;

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'password',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'username' => '[email protected]',
        'password' => 'my-password',
        'scope' => '',
    ],
]);

return json_decode((string) $response->getBody(), true);

:::tip TIP
Recuerda, los tokens de acceso son de larga duración de forma predeterminada. Sin embargo, eres libre de configurar la duración máxima del token de acceso si es necesario.
:::

Solicitando todos los alcances

Al usar el permiso de contraseña o el permiso de credenciales de clientes, es posible que desees autorizar el token para todos los alcances soportados por tu aplicación. Puedes hacer esto solicitando el alcance *. Si solicitas el alcance *, el método can en la instancia del token siempre devolverá true. Este alcance solo puede asignarse a un token que es emitido usando el permiso password o client_credentials:

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'password',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'username' => '[email protected]',
        'password' => 'my-password',
        'scope' => '*',
    ],
]);

Personalizando el campo username

Al autenticar usando el permiso de contraseña, Passport usará el atributo email de tu modelo como el «username». Sin embargo, puedes personalizar este comportamiento definiendo un método findForPassport en tu modelo:

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
        * Find the user instance for the given username.
        *
        * @param  string  $username
        * @return \App\User
        */
    public function findForPassport($username)
    {
        return $this->where('username', $username)->first();
    }
}

Personalizando la validación de la contraseña

Al autenticar usando el permiso de contraseña, Passport usará el atributo password de tu modelo para validar la contraseña dada. Si tu modelo no tiene un atributo password o deseas personalizar la lógica de validación de la contraseña, puedes definir un método validateForPassportPasswordGrant en tu modelo:

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
        * Validate the password of the user for the Passport password grant.
        *
        * @param  string  $password
        * @return bool
        */
    public function validateForPassportPasswordGrant($password)
    {
        return Hash::check($password, $this->password);
    }
}

Tokens de permiso implícito

El permiso implícito es similar al permiso de código de autorización; sin embargo, el token es devuelto al cliente sin intercambiar un código de autorización. Este permiso es usado con mayor frecuencia para Javascript o aplicaciones móviles donde las credenciales del cliente no se pueden almacenar de forma segura. Para habilitar este permiso, llama al método enableImplicitGrant en tu AuthServiceProvider:

/**
    * Register any authentication / authorization services.
    *
    * @return void
    */
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    Passport::enableImplicitGrant();
}

Una vez que se ha habilitado un permiso, los desarrolladores pueden usar el ID del cliente para solicitar un token de acceso de tu aplicación. La aplicación consumidora debe hacer una solicitud de redirección a la ruta /oauth/authorize de tu aplicación de la siguiente manera:

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://example.com/callback',
        'response_type' => 'token',
        'scope' => '',
        'state' => $state,
    ]);

    return redirect('http://your-app.com/oauth/authorize?'.$query);
});

:::tip TIP
Recuerda, la ruta /oauth/authorize ya está definida por el método Passport::routes. No necesitas definir esta ruta manualmente.
:::

Tokens de permiso de credenciales de cliente

El permiso de credenciales de clientes es adecuado para la autenticación máquina-a-máquina. Por ejemplo, podrías usar este permiso en un trabajo programado que realice una tarea de mantenimiento a través de una API.

Antes de que tu aplicación pueda emitir tokens por medio del permiso de credenciales de cliente, necesitarás crear un cliente con permiso de credenciales de clientes. Puedes hacer esto usando la opción --client del comando passport:client:

php artisan passport:client --client

A continuación, para usar este tipo de permiso, necesitas agregar el middleware CheckClientCredentials a la propiedad $routeMiddleware de tu archivo app/Http/Kernel.php:

use Laravel\Passport\Http\Middleware\CheckClientCredentials;

protected $routeMiddleware = [
    'client' => CheckClientCredentials::class,
];

Ahora, añade al middleware a una ruta:

Route::get('/orders', function (Request $request) {
    ...
})->middleware('client');

Para el acceso restringido a la ruta a alcances específicos, puedes proporcionar una lista delimitada por comas de los alcances requeridos al añadir el middleware client a la ruta:

Route::get('/orders', function (Request $request) {
    ...
})->middleware('client:check-status,your-scope');

Recuperando Tokens

Para recuperar un token usando este tipo de permiso, debes hacer una solicitud al endpoint oauth/token:

$guzzle = new GuzzleHttp\Client;

$response = $guzzle->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'client_credentials',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => 'your-scope',
    ],
]);

return json_decode((string) $response->getBody(), true)['access_token'];

Tokens de acceso personal

A veces, es posible que tus usuarios quieran emitir tokens de acceso a sí mismos sin pasar por el típico flujo de redirección del código de autorización. Permitir que los usuarios emitan tokens a sí mismos a través de la interfaz de tu aplicación puede ser útil para permitir que los usuarios experimenten con tu API o puede servir como un enfoque más sencillo para emitir tokens de acceso en general.

Creando un cliente de acceso personal

Antes que tu aplicación pueda emitir tokens de acceso personal, necesitarás crear un cliente de acceso personal. Puedes hacer esto usando el comando passport:client con la opción --personal. Si ya has ejecutado el comando passport:install, no necesitas ejecutar este comando:

php artisan passport:client --personal

Si ya has definido un cliente de acceso personal, puedes indicarle a Passport que lo use mediante el método personalAccessClientId. Normalmente, este método debe ser llamado desde el método boot de tu AuthServiceProvider:

/**
    * Register any authentication / authorization services.
    *
    * @return void
    */
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    Passport::personalAccessClientId('client-id');
}

Administrando tokens de acceso personal

Una vez que se ha creado un cliente de acceso personal, puedes enviar tokens para un usuario dado usando el método createToken en la instancia de modelo User. El método createToken acepta el nombre del token como primer argumento y un arreglo opcional de alcances como segundo argumento:

$user = App\User::find(1);

// Creating a token without scopes...
$token = $user->createToken('Token Name')->accessToken;

// Creating a token with scopes...
$token = $user->createToken('My Token', ['place-orders'])->accessToken;

API JSON

Passport también incluye un API JSON para administrar tokens de acceso personal. Puedes combinarlo con tu propio frontend para ofrecer a tus usuarios un panel de control para administrar los tokens de acceso personal. A continuación, revisaremos todos los endpoints del API para administrar tokens de acceso personal. Por comodidad, usaremos Axios para demostrar cómo realizar solicitudes HTTP a los endpoints.

La API JSON está protegida por los middleware web y auth; por lo tanto, sólo puede ser llamada desde tu propia aplicación. No se puede llamar desde una fuente externa.

Si no quieres implementar el frontend del token de acceso personal tu mismo, puedes usar el inicio rápido de frontend para tener un frontend completamente funcional en sólo minutos.

GET /oauth/scopes

Esta ruta devuelve todos los alcances definidos para tu aplicación. Puedes usar esta ruta para listar los alcances que un usuario puede asignar a un token de acceso personal:

axios.get('/oauth/scopes')
    .then(response => {
        console.log(response.data);
    });

GET /oauth/personal-access-tokens

Esta ruta devuelve todos los tokens de acceso personal que el usuario autenticado ha creado. Esto es útil principalmente para listar todos los tokens del usuario para que puedan editarlos o eliminarlos:

axios.get('/oauth/personal-access-tokens')
    .then(response => {
        console.log(response.data);
    });

POST /oauth/personal-access-tokens

Esta ruta crea nuevos tokens de acceso personal. Requiere dos datos: el name del token y el scopes que debe ser asignado al token:

const data = {
    name: 'Token Name',
    scopes: []
};

axios.post('/oauth/personal-access-tokens', data)
    .then(response => {
        console.log(response.data.accessToken);
    })
    .catch (response => {
        // List errors on response...
    });

DELETE /oauth/personal-access-tokens/{token-id}

Esta ruta se puede usar para eliminar tokens de acceso personal:

axios.delete('/oauth/personal-access-tokens/' + tokenId);

Protegiendo rutas

Por medio de middleware

Passport incluye un guard de autenticación que validará los tokens de acceso en las solicitudes entrantes. Una vez que has configurado el guard api para usar el driver passport, sólo necesitas especificar el middleware auth:api en cualquier ruta que requiera token de acceso válido:

Route::get('/user', function () {
    //
})->middleware('auth:api');

Pasando el token de acceso

Al llamar rutas que son protegidas por Passport, los consumidores del API de tu aplicación deben especificar su token de acceso como un token Bearer en el encabezado Authorization de su solicitud. Por ejemplo, al usar la librería Guzzle HTTP:

$response = $client->request('GET', '/api/user', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer '.$accessToken,
    ],
]);

Alcances de token

Los alcances permiten a tus clientes de la API solicitar un conjunto específico de permisos cuando solicitan autorización para acceder a una cuenta. Por ejemplo, si estás construyendo una aplicación de comercio electrónico, no todos los consumidores de la API necesitarán la capacidad de hacer pedidos. En lugar de eso, puedes permitir que los consumidores sólo soliciten autorización para acceder a los estados de envío del pedido. En otras palabras, los alcances permiten a los usuarios de tu aplicación limitar las acciones que una aplicación de terceros puede realizar en su nombre.

Definiendo alcances

Puedes definir los alcances de tu API usando el método Passport::tokensCan en el método boot de tu AuthServiceProvider. El método tokensCan acepta un arreglo de nombres de alcance y descripciones del alcance. La descripción del alcance puede ser cualquier cosa que desees y se mostrará a los usuarios en la pantalla de aprobación de autorización.

use Laravel\Passport\Passport;

Passport::tokensCan([
    'place-orders' => 'Place orders',
    'check-status' => 'Check order status',
]);

Alcance predeterminado

Si un cliente no solicita ningún alcance específico, puedes configurar tu servidor Passport para añadir un alcance predeterminado al token usando el método setDefaultScope. Normalmente, debes llamar a este método desde del método boot de tu AuthServiceProvider:

use Laravel\Passport\Passport;

Passport::setDefaultScope([
    'check-status',
    'place-orders',
]);

Asignando alcances a los Tokens

Al solicitar códigos de autorización

Al solicitar un token de acceso usando el permiso de código de autorización, los consumidores deben especificar sus alcances deseados como el parámetro de cadena de consulta scope. El parámetro scope debe ser una lista de alcances delimitada por espacios:

Route::get('/redirect', function () {
    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://example.com/callback',
        'response_type' => 'code',
        'scope' => 'place-orders check-status',
    ]);

    return redirect('http://your-app.com/oauth/authorize?'.$query);
});

Al emitir tokens de acceso personal

Si estás emitiendo tokens de acceso personal usando el método createToken del modelo User, puedes pasar el arreglo de alcances deseados como segundo argumento al método:

$token = $user->createToken('My Token', ['place-orders'])->accessToken;

Verificando alcances

Passport incluye dos middleware que pueden ser usados para verificar que una solicitud entrante es autenticada con un token al que se le ha otorgado un alcance dado. Para empezar, agrega el siguiente middleware a la propiedad $routeMiddleware de tu archivo app/Http/Kernel.php:

'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,

Verificar todos los alcances

El middleware scopes puede ser asignado a una ruta para verificar que el token de acceso de la solicitud entrante tiene todos los alcances listados:

Route::get('/orders', function () {
    // Access token has both "check-status" and "place-orders" scopes...
})->middleware(['auth:api', 'scopes:check-status,place-orders']);

Verificar si hay alcances

El middleware scope puede ser asignado a una ruta para verificar que el token de acceso de la solicitud entrante tiene al menos uno de los alcances listados:

Route::get('/orders', function () {
    // Access token has either "check-status" or "place-orders" scope...
})->middleware(['auth:api', 'scope:check-status,place-orders']);

Verificar alcances en una instancia de token

Una vez que una solicitud autenticada de token de acceso ha entrado en tu aplicación, puedes verificar si el token tiene un alcance dado usando el método tokenCan en la instancia User autenticada:

use Illuminate\Http\Request;

Route::get('/orders', function (Request $request) {
    if ($request->user()->tokenCan('place-orders')) {
        //
    }
});

Métodos de alcance adicionales

El método scopeIds devolverá un arreglo de todos los IDs / nombres definidos:

Laravel\Passport\Passport::scopeIds();

El método scopes devolverá un arreglo de todos los alcances definidos como instancias de Laravel\Passport\Scope:

Laravel\Passport\Passport::scopes();

El método scopesFor devolverá un arreglo de instancias Laravel\Passport\Scope que coincidan con los IDs / nombres dados:

Laravel\Passport\Passport::scopesFor(['place-orders', 'check-status']);

Puedes determinar si un alcance dado ha sido definido usando el método hasScope:

Laravel\Passport\Passport::hasScope('place-orders');

Consumiendo tu API con JavaScript

Cuando se construye una API, puede ser extremadamente útil poder consumir tu propia API desde tu aplicación JavaScript. Este enfoque para el desarrollo de la API permite que tu propia aplicación consuma la misma API que estás compartiendo con el mundo. La misma API puede ser consumida por tu aplicación web, aplicaciones móviles, aplicaciones de terceros y cualquier SDK que puedas publicar en varios gestores de paquetes.

Normalmente, si quieres consumir tu API desde tu aplicación Javascript, necesitarás enviar manualmente un token de acceso a la aplicación y pasarlo con cada solicitud a tu aplicación. Sin embargo, Passport incluye un middleware que puede manejar esto por ti. Todo lo que necesitas hacer es agregar el middleware CreateFreshApiToken a tu grupo de middleware web en tu archivo app/Http/Kernel.php:

'web' => [
    // Other middleware...
    \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

:::danger Nota
Debes asegurarte que el middleware CreateFreshApiToken es el último middleware que aparece en tu pila de middleware.
:::

Este middleware de Passport agregará una cookie laravel_token en tus respuestas salientes. Este cookie contiene un JWT encriptado que Passport utilizará para autenticar las solicitudes de API desde tu aplicación JavaScript. Ahora, puedes hacer solicitudes a la API de tu aplicación sin pasar explícitamente un token de acceso:

axios.get('/api/user')
    .then(response => {
        console.log(response.data);
    });

Personalizando el nombre de la cookie

Si es necesario, puedes personalizar el nombre de la cookie laravel_token usando el método Passport::cookie. Normalmente, deberías llamar a este método desde el método boot de tu AuthServiceProvider:

/**
    * Register any authentication / authorization services.
    *
    * @return void
    */
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    Passport::cookie('custom_name');
}

Protección CSRF

Al usar este método de autenticación, necesitarás asegurarte que se incluya un encabezado de token CSRF válido en tus solicitudes. El scaffolding Javascript de Laravel por defecto incluye una instancia Axios, que usará automáticamente el valor de la cookie XSRF-TOKEN encriptado para enviar un encabezado X-XSRF-TOKEN en solicitudes del mismo origen.

:::tip TIP
Si eliges enviar el encabezado X-CSRF-TOKEN en lugar de X-XSRF-TOKEN, necesitarás usar el token no encriptado proporcionado por csrf_token().
:::

Eventos

Passport genera eventos cuando se emiten tokens de acceso y tokens de actualización. Puedes usar estos eventos para eliminar o revocar otros tokens de acceso en tu base de datos. Puedes añadir listeners a estos eventos en el EventServiceProvider de tu aplicación:

/**
    * The event listener mappings for the application.
    *
    * @var array
    */
protected $listen = [
    'Laravel\Passport\Events\AccessTokenCreated' => [
        'App\Listeners\RevokeOldTokens',
    ],

    'Laravel\Passport\Events\RefreshTokenCreated' => [
        'App\Listeners\PruneOldTokens',
    ],
];

Pruebas

El método actingAs de Passport puede ser usado para especificar el usuario autenticado actualmente, así como sus alcances. El primer argumento dado al método actingAs es la instancia del usuario y el segundo es un arreglo de alcances que deben ser otorgados al token del usuario:

use App\User;
use Laravel\Passport\Passport;

public function testServerCreation()
{
    Passport::actingAs(
        factory(User::class)->create(),
        ['create-servers']
    );

    $response = $this->post('/api/create-server');

    $response->assertStatus(201);
}

El método actingAsClient de Passport puede ser usado para especificar el cliente autenticado actualmente, así como sus alcances. El primer argumento dado al método actingAsClient es la instancia del cliente y el segundo es un arreglo de alcances que deben ser otorgados al token del cliente:

use Laravel\Passport\Client;
use Laravel\Passport\Passport;

public function testGetOrders()
{
    Passport::actingAsClient(
        factory(Client::class)->create(),
        ['check-status']
    );

    $response = $this->get('/api/orders');

    $response->assertStatus(200);
}

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Laravel Horizon - Documentación de Laravel 6 Lección siguiente Scout para Laravel - Documentación de Laravel 6