Security for Web Developers
Authentication and Authorization
Password hashing, sessions, tokens, Gates, and Policies
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:
- Laravel generates a random session ID.
- The session ID is stored in an encrypted cookie (
laravel_session). - Session data (including the authenticated user's ID) is stored server-side (file, database, or Redis).
- 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
Authorizationheader: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 me anything about this lesson.
I have the full lesson content as context.