Usar JSON Web Tokens (JWT) con Laravel para Crear APIs Seguras
Utilizar JWT para autenticar usuarios a través de APIs es especialmente útil pues no se necesita implementar sesiones en el servidor y el JWT en sí mismo contiene la información correspondiente al usuario que realiza la petición por lo que sirve para validar la autenticidad del mismo.
Primero que nada necesitamos instalar Laravel y crear un proyecto. Instrucciones para instalar Laravel 5.8. Luego de tener instalado Laravel procedemos a crear un proyecto.
$ laravel new webpagePara implementar JWT en Laravel utilizaremos el módulo llamado tymondesigns/jwt-auth con el siguiente código:
$ composer require tymon/jwt-auth:dev-develop --prefer-sourceLuego para generar el archivo de configuración corremos el siguiente código:
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"Procedemos a generar una llave para nuestro proyecto:
$ php artisan jwt:secretPara que Laravel se conecte automáticamente a nuestra base de datos y la utiliza como método de validación de usuarios. Debemos crear una tabla users con las siguientes columnas:
idPRIMARY KEY AUTOINCREMENTnameVARCHARsurnameVARCHARemailVARCHARpasswordVARCHARcreate_atTIMESTAMPupdated_atTIMESTAMP
El modelo User utilizará por defecto la tabla users. Si se quiere especificar otro nombre para la tabla, se le puede definir el nombre a usar en app\User.php con el siguiente código:
...
protected $table = ''; // colocamos el nombre de la tabla
...Los pasos que siguen a continuación son a nivel de código. Necesitamos implementar Tymon\JWTAuth\Contracts\JWTSubject en el modelo de User. En este modelo debemos implementar dos métodos: getJWTIdentifier() y getJWTCustomClaims().
El modelo de User en app\User.php debería quedar similar a este:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject {
use Notifiable;
protected $fillable = [
'name', 'surname', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier() {
return $this->getKey();
}
public function getJWTCustomClaims() {
return [];
}
}Ahora para que Laravel utilice JWT como método de autenticación, abrimos el archivo config/auth.php y modificamos los siguientes datos:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
...
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],Ahora procedemos a agregar el controlador de autenticación. Lo llamaremos AuthController. Podemos crearlo manualmente o con el siguiente comando:
$ php artisan make:controller AuthControllerEn este controlador colocamos el siguiente código:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\RegisterAuthRequest;
use App\User;
use Illuminate\Http\Request;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class AuthController extends Controller {
public $loginAfterSignUp = true;
public function register(Request $request) {
$user = new User();
$user->name = $request->name;
$user->surname = $request->surname;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->loginAfterSignUp) {
return $this->login($request);
}
return response()->json([
'status' => 'ok',
'data' => $user
], 200);
}
public function login(Request $request) {
$input = $request->only('email', 'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'status' => 'invalid_credentials',
'message' => 'Correo o contraseña no válidos.',
], 401);
}
return response()->json([
'status' => 'ok',
'token' => $jwt_token,
]);
}
public function logout(Request $request) {
$this->validate($request, [
'token' => 'required'
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
'status' => 'ok',
'message' => 'Cierre de sesión exitoso.'
]);
} catch (JWTException $exception) {
return response()->json([
'status' => 'unknown_error',
'message' => 'Al usuario no se le pudo cerrar la sesión.'
], 500);
}
}
public function getAuthUser(Request $request) {
$this->validate($request, [
'token' => 'required'
]);
$user = JWTAuth::authenticate($request->token);
return response()->json(['user' => $user]);
}
}Ahora creamos las rutas que accederan a estos métdos en routes\api.php:
<?php
use Illuminate\Http\Request;
// estas rutas se pueden acceder sin proveer de un token válido.
Route::post('/login', 'AuthController@login');
Route::post('/register', 'AuthController@register');
// estas rutas requiren de un token válido para poder accederse.
Route::group(['middleware' => 'auth.jwt'], function () {
Route::post('/logout', 'AuthController@logout');
});Adicionalmente podemos añadir al comienzo del public\index.php el siguiente código para evitar error de CORS durante nuestras pruebas:
// permite peticiones desde cualquier origen
header('Access-Control-Allow-Origin: *');
// permite peticiones con métodos GET, PUT, POST, DELETE y OPTIONS
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
// permite los headers Content-Type y Authorization
header('Access-Control-Allow-Headers: Content-Type, Authorization');Esto concluye la parte de la cofiguración de Laravel para utilizar JSON Web Tokens. Ahora procedemos a hacer algunas peticiones de prueba utilizando Insomnia para comprobar que nuestras rutas están funcionando.
Realizamos una petición a la ruta /api/register y confirmamos que recibimos un status: ok y un token.

Esto quiere decir que en la base de datos se registró este usuario y se generó un token de forma automática que debemos enviar con cada petición a rutas protegidas.
Podemos también probar /api/login.

El token lo podemos enviar en cada petición de distintas formas.
- Podemos hacerlo por url en el caso de usar
GETpor ejemplo.../api/products?token=eyJ0eXAiOiJ.... - Como una propiedad de un JSON enviado en un
POST. - O como parte del header
Authorization: Bearer eyJ0eXAiOiJ.... Aprende más.
En el siguiente ejemplo lo enviamos como una propiedad en un JSON para desloguear al usuario usando api/logout.

De la misma forma podríamos continuar creando más rutas protegidas las cuales requerirían de un token válido para ser accedidas. Como siempre cualquier duda la pueden dejar en los comentarios. Saludos.

