Cookie-based session authentication for traditional web applications.
Session mode provides:
# config/packages/better_auth.yaml
better_auth:
mode: 'session'
secret: '%env(BETTER_AUTH_SECRET)%'
session:
lifetime: 604800 # 7 days
cookie_name: 'better_auth_session'
┌──────────┐ ┌──────────┐
│ Browser │ │ Server │
└────┬─────┘ └────┬─────┘
│ │
│ POST /auth/login │
│ {email, password} │
├──────────────────────────────────────────────►
│ │
│ Set-Cookie: better_auth_session=xxx │
│ {user} │
◄──────────────────────────────────────────────┤
│ │
│ GET /api/resource │
│ Cookie: better_auth_session=xxx │
├──────────────────────────────────────────────►
│ │
│ {data} │
◄──────────────────────────────────────────────┤
curl -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email":"user@example.com","password":"password123"}'
Response:
{
"access_token": "session_token_xxx",
"refresh_token": "session_token_xxx",
"expires_in": 604800,
"token_type": "Bearer",
"user": {
"id": "019ab13e-40f1-7b21-a672-f403d5277ec7",
"email": "user@example.com",
"username": "John Doe"
}
}
Cookie set:
Set-Cookie: better_auth_session=xxx; HttpOnly; Secure; SameSite=Lax; Path=/
curl -X GET http://localhost:8000/api/me \
-b cookies.txt
curl -X POST http://localhost:8000/auth/logout \
-b cookies.txt
Cookies are set with:
HttpOnly - Not accessible via JavaScriptSecure - Only sent over HTTPSSameSite=Lax - CSRF protectionSessions are stored in the database with:
// Session entity stores:
$session->getToken(); // Session identifier
$session->getUserId(); // Associated user
$session->getIpAddress(); // Client IP
$session->getMetadata(); // Device, browser, OS, location
$session->getCreatedAt(); // Creation time
$session->getExpiresAt(); // Expiration time
# config/packages/security.yaml
security:
providers:
better_auth:
id: BetterAuth\Symfony\Security\BetterAuthUserProvider
firewalls:
main:
pattern: ^/
stateless: false # Enable sessions
provider: better_auth
custom_authenticators:
- BetterAuth\Symfony\Security\BetterAuthAuthenticator
logout:
path: /auth/logout
target: /
access_control:
- { path: ^/auth, roles: PUBLIC_ACCESS }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/, roles: ROLE_USER }
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
<p>Welcome, {{ app.user.email }}!</p>
<a href="{{ path('auth_logout') }}">Logout</a>
{% else %}
<a href="{{ path('auth_login') }}">Login</a>
{% endif %}
{% if app.user %}
<div class="user-info">
<p>Name: {{ app.user.username }}</p>
<p>Email: {{ app.user.email }}</p>
<p>Verified: {{ app.user.emailVerified ? 'Yes' : 'No' }}</p>
</div>
{% endif %}
{% if is_granted('ROLE_ADMIN') %}
<a href="{{ path('admin_dashboard') }}">Admin Dashboard</a>
{% endif %}
curl -X GET http://localhost:8000/auth/sessions \
-b cookies.txt
Response:
{
"sessions": [
{
"id": "sess_xxx",
"device": "Desktop",
"browser": "Chrome 120",
"os": "Windows 11",
"ip": "192.168.1.1",
"location": "Paris, France",
"current": true,
"createdAt": "2024-01-15T10:00:00Z",
"lastActiveAt": "2024-01-15T14:30:00Z",
"expiresAt": "2024-01-22T10:00:00Z"
},
{
"id": "sess_yyy",
"device": "Mobile",
"browser": "Safari",
"os": "iOS 17",
"ip": "10.0.0.1",
"location": "London, UK",
"current": false,
"createdAt": "2024-01-14T08:00:00Z",
"lastActiveAt": "2024-01-14T12:00:00Z",
"expiresAt": "2024-01-21T08:00:00Z"
}
]
}
curl -X DELETE http://localhost:8000/auth/sessions/sess_yyy \
-b cookies.txt
curl -X POST http://localhost:8000/auth/revoke-all \
-b cookies.txt
# config/packages/better_auth.yaml
better_auth:
session:
cookie_name: 'better_auth_session'
# Cookies work on localhost without HTTPS
Ensure HTTPS is enabled for secure cookies:
# config/packages/framework.yaml
framework:
session:
cookie_secure: true
cookie_httponly: true
cookie_samesite: lax
| Duration | Seconds | Use Case |
|---|---|---|
| 1 hour | 3600 | High security |
| 24 hours | 86400 | Daily users |
| 7 days | 604800 | Default, balanced |
| 30 days | 2592000 | Remember me |
| 90 days | 7776000 | Long-lived |
better_auth:
session:
lifetime: 2592000 # 30 days for "remember me"
For forms that modify data, include CSRF token:
<form method="post" action="{{ path('user_settings') }}">
<input type="hidden" name="_token" value="{{ csrf_token('settings') }}">
<!-- form fields -->
<button type="submit">Save</button>
</form>
// Controller
#[Route('/settings', methods: ['POST'])]
public function settings(Request $request): Response
{
if (!$this->isCsrfTokenValid('settings', $request->request->get('_token'))) {
throw new InvalidCsrfTokenException();
}
// Process form
}
How can I help you explore Laravel packages today?