Skip to content

Instantly share code, notes, and snippets.

@atomjoy
Last active September 3, 2025 12:04
Show Gist options
  • Save atomjoy/b4384ed8796874401d7d9c8a2ec8270e to your computer and use it in GitHub Desktop.
Save atomjoy/b4384ed8796874401d7d9c8a2ec8270e to your computer and use it in GitHub Desktop.
Jak dodać role i uprawnienia do zalogowanego użytkownika z Sanctum w Laravel.

Laravel Sanctum Spatie Permissions

Jak dodać role i uprawnienia do zalogowanego użytkownika z Sanctum w Laravel.

Zalogowany user

W sanctum ładujesz relacje za pomocą ->fresh(['roles','permissions']) dla zalogowanego użytkownika.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;

Route::name('api.')->group(function () {
    // All logged
    Route::middleware(['auth:sanctum'])->group(function () {
        // User
        Route::get('/user', function (Request $request) {
            // Return model with relations and attributes
            return Auth::user()->fresh(['roles', 'permissions'])->toArray(); 
        })->name('user');
    });
});

User model

Lub w modelu użytkownika dodajesz attrybut permission przez $appends co zaczyta automatycznie relacje roles, i permissions.

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable;
    use HasApiTokens;
    use HasRoles;

    /**
     * Default guard name
     *
     * @var string
     */
    protected $guard = 'web';

    /**
     * Display relations with model
     *
     * @var array
     */
    // protected $with = ['roles', 'permissions'];

    /**
     * Display relations with model (appends roles and permissions with sanctum logged user)
     *
     * @var array
     */
    protected $appends = ['permission'];

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'password' => 'hashed',
            'email_verified_at' => 'datetime:Y-m-d H:i:s',
            'created_at' => 'datetime:Y-m-d H:i:s',
            'updated_at' => 'datetime:Y-m-d H:i:s',
            'deleted_at' => 'datetime:Y-m-d H:i:s',
        ];
    }

    /**
     * Default guard name permissions
     *
     * @var string
     */
    protected function getDefaultGuardName()
    {
        return $this->guard;
    }

    /**
     * Get all permissions (from roles and direct)
     *
     * @var string
     */
    protected function getPermissionAttribute()
    {
        return $this->getAllPermissions();
    }
}

Test

<?php

namespace Tests\Feature;

use App\Enums\Spatie\RolesEnum;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class SanctumTest extends TestCase
{
    use RefreshDatabase;

    /**
     * Logged user details
     *
     * @return void
     */
    public function test_api_user_only_logged(): void
    {
        $this->seed();

        $user = User::factory()->create();
        
        $role = app(Role::class)->findOrCreate('admin', 'web');

        $user->assignRole($role);

        $permission = app(Permission::class)->findOrCreate('user_view', 'web');

        $user->givePermissionTo($permission);

        Sanctum::actingAs($user, ['*'], 'web');

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

        $response->assertOk();

        $response->assertJsonStructure([
            "roles",
            "permissions",
            // "permission", // Only with appends
        ]);

        // Show in console
        // dd($response->decodeResponseJson());
    }
}

Expired Token middleware

/**
 * Sanctum expired token middleware.
 *
 * Add middleware in bootstrap/app.php
 * $middleware->api(prepend: [ \App\Http\Middleware\Api\ExpiredToken::class ]);
 */
class ExpiredToken
{
    public function handle(Request $request, Closure $next)
    {
        $bearer = $request->bearerToken();

        if ($bearer) {
            $token = PersonalAccessToken::findToken($bearer);

            if ($token instanceof PersonalAccessToken) {
                if($token->expires_at && $token->expires_at->isPast()) {
                    $request->merge([
                        'token_expired' => $token->expires_at && $token->expires_at->isPast(),
                        'token_details' => $token
                    ]);

                    return response()->json([
                        'message' => 'Expired Token.',
                        'token_expired' => $token->expires_at && $token->expires_at->isPast(),
                        'token_details' => $token
                    ], 403);
                }
            }
        }

        return $next($request);
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment