Last active
September 15, 2021 19:45
-
-
Save scrubmx/e0e1ccaad4c3014e685aca10cc4da343 to your computer and use it in GitHub Desktop.
Laravel Sanctum Authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use \Illuminate\Http\Request; | |
$router->post('login', AuthController::class)->name('api.login'); | |
$router->group(['middleware' => 'auth:sanctum'], function (Router $router) { | |
$router->get('user', function (Request $request) { | |
return response()->json($request->user()); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Controllers\Api; | |
use App\Models\User; | |
use Illuminate\Http\Request; | |
use Illuminate\Support\Facades\Hash; | |
use Illuminate\Support\Str; | |
use Illuminate\Validation\ValidationException; | |
class AuthController | |
{ | |
public function __invoke(Request $request) | |
{ | |
$request->validate([ | |
'email' => ['required', 'email'], | |
'password' => 'required', | |
'device_name' => ['sometimes', 'nullable'], | |
]); | |
/** @var User */ | |
$user = User::where('email', $request->post('email'))->first(); | |
if (! $user || ! Hash::check($request->post('password'), $user->password)) { | |
throw ValidationException::withMessages([ | |
'email' => ['The provided credentials are incorrect.'], | |
]); | |
} | |
// At this time, there is no way to retrieve an existing token stored in DB. | |
// We need to create a new token each time the user log in | |
// @link https://github.com/laravel/sanctum/issues/37 | |
$user->tokens()->delete(); | |
$token = $user->createToken($request->post('device_name') ?? Str::random()); | |
return response()->json(['token' => $token->plainTextToken]); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tests\Feature\Api; | |
use App\Models\User; | |
use Illuminate\Foundation\Testing\RefreshDatabase; | |
use Illuminate\Support\Str; | |
use Tests\TestCase; | |
class AuthenticationTest extends TestCase | |
{ | |
use RefreshDatabase; | |
/** @test */ | |
public function required_fields_are_validated_on_login() | |
{ | |
$this->postJson(route('api.login')) | |
->assertJsonValidationErrors(['email', 'password']); | |
} | |
/** @test */ | |
public function login_without_device_name() | |
{ | |
/** @var User */ | |
$user = User::factory()->create([ | |
'email' => '[email protected]', | |
'password' => bcrypt('secret'), | |
]); | |
$this->postJson(route('api.login'), [ | |
'email' => '[email protected]', | |
'password' => 'secret', | |
]) | |
->assertOk() | |
->assertJsonStructure(['token']); | |
// After logged in, user should have only 1 token | |
$this->assertEquals(1, $user->tokens()->count()); | |
} | |
/** @test */ | |
public function login_with_device_name() | |
{ | |
/** @var User */ | |
$user = User::factory()->create([ | |
'email' => '[email protected]', | |
'password' => bcrypt('secret'), | |
]); | |
$this->postJson(route('api.login'), [ | |
'email' => '[email protected]', | |
'password' => 'secret', | |
'device_name' => "Nuno's iPhone 12", | |
]) | |
->assertOk() | |
->assertJsonStructure(['token']); | |
// After logged in, user should have only 1 token | |
$this->assertEquals(1, $user->tokens()->count()); | |
// Device name should exist in DB | |
$this->assertDatabaseHas('personal_access_tokens', [ | |
'tokenable_type' => $user->getMorphClass(), | |
'tokenable_id' => $user->id, | |
'name' => "Nuno's iPhone 12", | |
]); | |
} | |
/** @test */ | |
public function sanctum_resolves_user_model_from_the_request() | |
{ | |
// Having a user with an api token | |
/** @var \App\Models\User */ | |
$user = User::factory()->create(); | |
$token = $user->createToken(Str::random())->plainTextToken; | |
$this->withToken($token) | |
->getJson('/api/user') | |
->assertOk(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment