Authentication and authorization

Laravel · Practical · 16 min

Every app needs to know who the user is and what they may do, and getting either wrong is a security hole.

Authentication answers "who are you?". The fastest start is a starter kit (React, Vue or Livewire), which generates login, registration, password reset and email verification. Underneath they use simple APIs you can also call yourself:

  • Auth::attempt(['email' => $e, 'password' => $p], $remember) checks credentials (passwords are hashed with bcrypt via the hashed cast on the User model).
  • After a successful login call $request->session()->regenerate() to prevent session fixation; on logout Auth::logout(), then invalidate the session and regenerate the CSRF token.
  • auth()->user() or $request->user() returns the current user; Auth::check() tells you if anyone is logged in.
  • Protect routes with the auth middleware; guests are redirected to the login route.

For APIs and SPAs, Sanctum issues API tokens or uses cookie-based SPA authentication.

Authorization answers "may you do this?".

  • Gates are closures for general abilities: Gate::define('view-reports', fn (User $u) => $u->is_admin);.
  • Policies group rules for one model: php artisan make:policy PostPolicy --model=Post creates methods like update(User $user, Post $post). They're discovered automatically by naming convention.

Check permissions with Gate::authorize('update', $post) (throws a 403), $user->can('update', $post), the can:update,post middleware, or @can in Blade. Always authorize on the server, even if the UI hides the button.

Example

<?php
// app/Policies/PostPolicy.php
class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

class SessionController extends Controller
{
    public function store(Request $request)
    {
        $credentials = $request->validate(['email' => 'required|email', 'password' => 'required']);
        if (! Auth::attempt($credentials, $request->boolean('remember'))) {
            return back()->withErrors(['email' => 'Invalid credentials.'])->onlyInput('email');
        }
        $request->session()->regenerate();
        return redirect()->intended('/dashboard');
    }
}
// PostController@update:   Gate::authorize('update', $post);   // 403 if not allowed
// routes/web.php:          Route::put('/posts/{post}', ...)->middleware(['auth', 'can:update,post']);
// Blade:                   @can('update', $post) <a href="...">Edit</a> @endcan

Remember

  • Auth::attempt logs in; regenerate the session afterwards
  • Policies hold per-model rules; gates hold general abilities
  • Authorize on the server with Gate::authorize, can middleware or $user->can

Watch out for

  • Hiding an Edit button with @can but not authorizing in the controller, so a crafted request still works.

Check yourself

  1. Where should the rule "only the author may edit a post" live in Laravel?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: laravel.com/docs/12.x/authorization