Session Endpoints
Session management API endpoints for viewing and revoking sessions
All endpoints require authentication headers:
Authorization: Bearer <access-token>
X-Session-Id: <session-id>Get Sessions
Retrieve all active sessions for the current user.
GET /api/sessionsExample
curl http://localhost:3000/api/sessions \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "X-Session-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890"{
"success": true,
"data": {
"sessions": [
{
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"authMethod": "email",
"browser": "Chrome 120.0.0",
"os": "macOS 14.2",
"device": "Desktop",
"ipAddress": "192.168.1.100",
"location": null,
"createdAt": "2024-01-15T10:30:00.000Z",
"lastActiveAt": "2024-01-15T14:22:00.000Z",
"revokedAt": null
},
{
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"authMethod": "github",
"browser": "Safari 17.2",
"os": "iOS 17.2",
"device": "iPhone",
"ipAddress": "10.0.0.50",
"location": null,
"createdAt": "2024-01-14T08:15:00.000Z",
"lastActiveAt": "2024-01-14T18:45:00.000Z",
"revokedAt": null
},
{
"sessionId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"authMethod": "google",
"browser": "Firefox 121.0",
"os": "Windows 11",
"device": "Desktop",
"ipAddress": "172.16.0.25",
"location": null,
"createdAt": "2024-01-13T16:00:00.000Z",
"lastActiveAt": "2024-01-13T20:30:00.000Z",
"revokedAt": null
}
]
}
}Session Fields
Prop
Type
The lastActiveAt timestamp is updated each time the user makes an authenticated API request.
Revoke Session
Terminate a specific session. The user will be logged out on that device.
DELETE /api/sessionsRequest Body
Prop
Type
Example
curl -X DELETE http://localhost:3000/api/sessions \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "X-Session-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f23456789012"
}'{
"success": true,
"message": "Session revoked successfully",
"data": {
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f23456789012"
}
}{
"success": false,
"message": "Cannot revoke your current session"
}{
"success": false,
"message": "Session not found"
}You cannot revoke your current session. Use the logout endpoint instead.
Session Lifecycle
Creation
Sessions are created when:
- User logs in with email/password
- User verifies email after registration
- User completes OAuth flow (GitHub/Google)
Metadata Collection
The session tracker parses the request to extract:
import { UAParser } from 'ua-parser-js';
const parser = new UAParser(request.headers.get('user-agent'));
const sessionData = {
browser: `${parser.getBrowser().name} ${parser.getBrowser().version}`,
os: `${parser.getOS().name} ${parser.getOS().version}`,
device: parser.getDevice().model || parser.getDevice().type || 'Desktop',
ipAddress: request.headers.get('x-forwarded-for') ||
request.headers.get('x-real-ip') ||
'unknown',
};Activity Tracking
The lastActiveAt timestamp is updated on each authenticated API request:
// In auth middleware
await touchSession(userAuthId, sessionId);Revocation
When a session is revoked:
revokedAtis set to current timestamp- Session is excluded from validation
- Any request with this session ID returns 401
Frontend Implementation
Sessions List
'use client';
import { useUserSessions, useRevokeSession } from '@/hooks/users/useUserSessions';
import { tokenManager } from '@/lib/config/token-manager';
export function SessionsList() {
const { data, isLoading } = useUserSessions();
const revokeSession = useRevokeSession();
const currentSessionId = tokenManager.getSessionId();
if (isLoading) return <div>Loading sessions...</div>;
return (
<div>
<h2>Active Sessions</h2>
{data?.sessions.map((session) => (
<div key={session.sessionId}>
<div>
<strong>{session.browser}</strong> on {session.os}
</div>
<div>
{session.device} - {session.ipAddress}
</div>
<div>
Last active: {new Date(session.lastActiveAt).toLocaleString()}
</div>
{session.sessionId === currentSessionId ? (
<span>Current session</span>
) : (
<button
onClick={() => revokeSession.mutate({ sessionId: session.sessionId })}
disabled={revokeSession.isPending}
>
Revoke
</button>
)}
</div>
))}
</div>
);
}Revoke All Other Sessions
To revoke all sessions except the current one:
async function revokeAllOtherSessions() {
const currentSessionId = tokenManager.getSessionId();
const { sessions } = await userService.getSessions();
const otherSessions = sessions.filter(
(s) => s.sessionId !== currentSessionId
);
await Promise.all(
otherSessions.map((s) =>
userService.revokeSession({ sessionId: s.sessionId })
)
);
}Security Considerations
- Session Validation: Every authenticated request validates the session is not revoked
- IP Tracking: IP addresses are recorded for audit purposes
- Device Fingerprinting: Browser and OS information helps identify unauthorized access
- Immediate Revocation: Revoked sessions are immediately invalidated
- Current Session Protection: Users cannot accidentally revoke their current session