Skip to content

Instantly share code, notes, and snippets.

@scrubmx
Last active September 15, 2021 19:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scrubmx/e0e1ccaad4c3014e685aca10cc4da343 to your computer and use it in GitHub Desktop.
Save scrubmx/e0e1ccaad4c3014e685aca10cc4da343 to your computer and use it in GitHub Desktop.
Laravel Sanctum Authentication
<?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());
});
});
<?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]);
}
}
<?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' => 'user@example.test',
'password' => bcrypt('secret'),
]);
$this->postJson(route('api.login'), [
'email' => 'user@example.test',
'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' => 'user@example.test',
'password' => bcrypt('secret'),
]);
$this->postJson(route('api.login'), [
'email' => 'user@example.test',
'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