Courses Developer Fundamentals for Builders Authentication and Authorization

Security for Web Developers

Authentication and Authorization

Password hashing, sessions, tokens, Gates, and Policies

12 min read · Lesson 11 of 18

Authentication vs Authorization

Authentication answers "Who are you?" — verifying identity via credentials. Authorization answers "What can you do?" — checking permissions. They're different systems that work together.


Password Hashing

Never store plain-text passwords. Laravel uses bcrypt by default (configurable to argon2), which is a one-way hash with a built-in salt:

$hash = Hash::make('password123');
// $2y$12$Ks8gR0wN3fL... (60 characters, different every time due to random salt)

Hash::check('password123', $hash); // true

Bcrypt is intentionally slow (~100ms per hash). This is a feature, not a bug — it makes brute-force attacks impractical. An attacker with a stolen database of bcrypt hashes would need ~100ms per guess, making dictionary attacks take years instead of minutes.


Sessions: Maintaining Login State

HTTP is stateless — each request is independent. Sessions bridge this gap. When a user logs in:

  1. Laravel generates a random session ID.
  2. The session ID is stored in an encrypted cookie (laravel_session).
  3. Session data (including the authenticated user's ID) is stored server-side (file, database, or Redis).
  4. On each subsequent request, the cookie is sent, the session is loaded, and the user is "remembered."

The auth middleware checks for a valid session. If none exists, it redirects to the login page.


API Tokens

For APIs, sessions don't work well (no browser, no cookies). Instead, use tokens. Laravel Sanctum provides two approaches:

  • SPA authentication — Uses the same session/cookie mechanism but for JavaScript frontends on the same domain.
  • API tokens — Generate a bearer token stored in the database. Include it in the Authorization header: Bearer your-token-here.

Gates and Policies

Gates are simple closures that determine if a user can perform an action:

Gate::define('update-post', function (User $user, Post $post) {
    return $user->id === $post->user_id;
});

Policies are classes that group authorization logic for a model:

class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }

    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id || $user->is_admin;
    }
}

Use them in controllers with $this->authorize('update', $post) or in Blade with @can('update', $post).


Key Takeaways

  • Bcrypt hashing is intentionally slow — it's a security feature.
  • Sessions maintain state via encrypted cookies + server-side storage.
  • Use Sanctum tokens for API authentication.
  • Gates (simple checks) and Policies (model-specific) handle authorization. Always authorize in controllers, not just in the view layer.
Ask about this lesson