3.5 KiB
3.5 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Manage Auth Tokens Properly | CRITICAL | Prevents unauthorized access, handles token expiration gracefully | authentication, tokens, refresh, security, session |
Manage Auth Tokens Properly
Auth tokens should be refreshed before expiration, validated on critical operations, and properly cleared on logout. The SDK's authStore handles most of this automatically.
Incorrect (ignoring token expiration):
// Bad: never checking token validity
async function fetchUserData() {
// Token might be expired!
const records = await pb.collection('posts').getList();
return records;
}
// Bad: manually managing tokens
let authToken = localStorage.getItem('token');
fetch('/api/posts', {
headers: { 'Authorization': authToken } // Token might be invalid
});
Correct (proper token management):
import PocketBase from 'pocketbase';
const pb = new PocketBase('http://127.0.0.1:8090');
// Check token validity before operations
async function fetchSecureData() {
// authStore.isValid is a client-side check only (JWT expiry parsing).
// Always verify server-side with authRefresh() for critical operations.
if (!pb.authStore.isValid) {
throw new Error('Please log in');
}
return pb.collection('posts').getList();
}
// Refresh token periodically or before expiration
async function refreshAuthIfNeeded() {
if (!pb.authStore.isValid) {
return false;
}
try {
// Verifies current token and returns fresh one
await pb.collection('users').authRefresh();
console.log('Token refreshed');
return true;
} catch (error) {
// Token invalid - user needs to re-authenticate
pb.authStore.clear();
return false;
}
}
// Auto-refresh on app initialization
async function initializeAuth() {
if (pb.authStore.token) {
try {
await pb.collection('users').authRefresh();
} catch {
pb.authStore.clear();
}
}
}
// Listen for auth changes and handle expiration
pb.authStore.onChange((token, record) => {
if (!token) {
// User logged out or token cleared
redirectToLogin();
}
});
// Setup periodic refresh (e.g., every 10 minutes)
setInterval(async () => {
if (pb.authStore.isValid) {
try {
await pb.collection('users').authRefresh();
} catch {
pb.authStore.clear();
}
}
}, 10 * 60 * 1000);
SSR / Server-side token handling:
// Server-side: create fresh client per request
export async function handleRequest(request) {
const pb = new PocketBase('http://127.0.0.1:8090');
// Load auth from cookie
pb.authStore.loadFromCookie(request.headers.get('cookie') || '');
// Validate and refresh
if (pb.authStore.isValid) {
try {
await pb.collection('users').authRefresh();
} catch {
pb.authStore.clear();
}
}
// ... handle request ...
// Send updated cookie with secure options
const response = new Response();
response.headers.set('set-cookie', pb.authStore.exportToCookie({
httpOnly: true, // Prevent XSS access to auth token
secure: true, // HTTPS only
sameSite: 'Lax', // CSRF protection
}));
return response;
}
Token configuration (Admin UI or migration):
// Configure token durations (superuser only)
await pb.collections.update('users', {
authToken: {
duration: 1209600 // 14 days in seconds
},
verificationToken: {
duration: 604800 // 7 days
}
});
Reference: PocketBase Auth Store