This document outlines the security architecture, known vulnerabilities, and best practices for the Basis Data LTT healthcare management system. Please read this carefully before deploying to production.
- Authentication & Password Security
- Current Security Issues
- Backend Requirements
- Frontend Security Measures
- Environment Variables
- Production Deployment
- Security Checklist
This is a FRONTEND application only. All password hashing and authentication logic MUST be implemented on the backend.
User Input → Frontend → Backend API → Database
(plain) (must hash)-
User Registration (
/therapist/register):- User enters email, password, and personal details
- Frontend sends password in plain text JSON to backend API
- Backend MUST hash password before storing in database
-
User Login (
/login):- User enters email and password
- Frontend sends credentials in plain text JSON to backend API
- Backend validates password hash and returns session token
-
Session Management:
- Backend returns session token upon successful login
- Frontend stores token in
localStorageassession-token - All subsequent API requests include this token in headers
Important: Password hashing is intentionally NOT performed on the frontend for these reasons:
- Security by Design: Client-side hashing would expose the hashing algorithm and make it easier for attackers to prepare attacks
- Salt Management: Proper password hashing requires unique salts per user, which must be securely generated and stored server-side
- Defense in Depth: If frontend hashing were used, the hash itself becomes the password, defeating the purpose
- Backend Validation: Only the backend can enforce proper password policies and use secure hashing algorithms
Issue: Passwords are sent in plain text JSON to the backend.
Files Affected:
src/app/login/page.tsx(lines 29-38)src/app/therapist/register/page.tsx(lines 43-64)
Current Code:
body: JSON.stringify({ email, password }) // ← Password in plain textRisk: If HTTPS is not enforced, passwords can be intercepted by man-in-the-middle attacks.
Mitigation:
- ✅ REQUIRED: Deploy backend with HTTPS/TLS enabled
- ✅ REQUIRED: Configure frontend to use
https://API endpoint in production - ✅ Implement HSTS (HTTP Strict Transport Security) on backend
- ✅ Use strong TLS/SSL certificates (TLS 1.2 or higher)
Issue: Default configuration uses HTTP protocol.
Files Affected:
.env.sample(line 2)- README.md configuration examples
Current Default:
NEXT_PUBLIC_API_HOST=https://localhost:19091Risk: Development habits may carry over to production, exposing credentials.
Mitigation:
- ✅ Always use HTTPS in production
- ✅ Update
.env.productionto enforce HTTPS URLs - ✅ Add validation to reject HTTP URLs in production builds
Issue: NEXT_PUBLIC_API_TOKEN is exposed to the browser.
Files Affected:
- All API calls using
Authorization: Bearer ${NEXT_PUBLIC_API_TOKEN}
Risk: Any user can inspect the browser console/network tab and extract this token.
Current Usage:
headers: {
'Authorization': 'Bearer ' + process.env.NEXT_PUBLIC_API_TOKEN,
'session-token': localStorage.getItem('session-token')
}Mitigation:
- ✅ Backend should ONLY rely on
session-tokenfor authentication - ✅
NEXT_PUBLIC_API_TOKENshould be removed or used only for non-sensitive operations ⚠️ NEVER use NEXTPUBLIC* variables for secrets
Issue: Session tokens stored in localStorage are vulnerable to XSS attacks.
Risk: If an attacker injects JavaScript (via XSS), they can steal session tokens.
Mitigation:
- ✅ Implement Content Security Policy (CSP) headers
- ✅ Sanitize all user inputs to prevent XSS
- ✅ Consider using httpOnly cookies for session management (requires backend changes)
- ✅ Implement short session timeouts and token rotation
Issue: Password strength requirements only checked in browser.
Files Affected:
src/app/therapist/register/page.tsx(therapist registration form password validation logic)
Risk: Attackers can bypass frontend validation by sending direct API requests.
Mitigation:
- ✅ Backend MUST validate password strength server-side
- ✅ Frontend validation is for UX only, not security
Issue: Password confirmation check happens only in the browser.
Mitigation:
- ✅ Keep client-side check for UX
- ✅ Backend should receive and validate both password fields
The backend API MUST implement the following security measures:
REQUIRED: Use a strong, adaptive hashing algorithm:
- ✅ Recommended: Argon2id (winner of Password Hashing Competition)
- ✅ Acceptable: bcrypt with cost factor ≥ 12
- ❌ NEVER USE: MD5, SHA1, SHA256, SHA512 without salt/iterations
Example (Node.js with bcrypt):
const bcrypt = require('bcrypt')
const saltRounds = 12
// Registration
const hashedPassword = await bcrypt.hash(plainPassword, saltRounds)
// Login
const match = await bcrypt.compare(plainPassword, hashedPassword)Example (Go with bcrypt):
import "golang.org/x/crypto/bcrypt"
// Registration
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plainPassword), 12)
// Login
err := bcrypt.CompareHashAndPassword(hashedPassword, []byte(plainPassword))Backend MUST enforce:
- ✅ Minimum 8 characters
- ✅ At least one uppercase letter
- ✅ At least one lowercase letter
- ✅ At least one number
- ✅ At least one special character (recommended)
- ✅ Maximum length limit (e.g., 72 bytes for bcrypt)
- ✅ Implement rate limiting on login endpoints (e.g., 5 attempts per 15 minutes)
- ✅ Use timing-safe password comparison to prevent timing attacks
- ✅ Never reveal whether email or password was incorrect (just say "invalid credentials")
- ✅ Log failed login attempts for security monitoring
- ✅ Implement account lockout after repeated failures
- ✅ Use secure session tokens (cryptographically random, minimum 128 bits)
- ✅ Set session expiration (e.g., 24 hours)
- ✅ Implement token rotation on sensitive actions
- ✅ Use TLS 1.2 or TLS 1.3 only
- ✅ Disable SSL/TLS compression
- ✅ Use strong cipher suites
- ✅ Implement HSTS header:
Strict-Transport-Security: max-age=31536000; includeSubDomains - ✅ Redirect all HTTP traffic to HTTPS
- Password Input Masking: Password fields use
type="password"to hide input - Client-Side Validation: Basic password strength validation for UX
- Session Token Management: Tokens stored and sent with each authenticated request
- 401 Handling: Automatic redirect to login on unauthorized access
Add real-time password strength indicator (see implementation below).
Add CSP headers in next.config.ts to mitigate XSS attacks:
'unsafe-inline' and 'unsafe-eval' in production as they defeat the purpose of CSP. Use nonces or hashes for inline scripts/styles.
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self'", // Remove 'unsafe-inline' and 'unsafe-eval'
"style-src 'self'", // Remove 'unsafe-inline'
"img-src 'self' data: https:",
"font-src 'self' data:",
"connect-src 'self'",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'"
].join('; ')
}
]
}
]
}For Next.js with inline scripts/styles, you may need to use nonces:
// In middleware or server component
const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
// CSP with nonce
const csp = `
default-src 'self';
script-src 'self' 'nonce-${nonce}';
style-src 'self' 'nonce-${nonce}';
`.replace(/\s{2,}/g, ' ').trim()
// Then use nonce in inline scripts/styles
<script nonce={nonce}>...</script>See Next.js CSP documentation for implementation details.
All user inputs should be sanitized to prevent XSS:
- Use React's built-in escaping (default for JSX)
- Avoid
dangerouslySetInnerHTMLunless absolutely necessary - Validate and sanitize on backend as well
NEXT_PUBLIC_ are embedded in the browser bundle and are publicly accessible.
NEVER store in NEXT_PUBLIC_* variables:
- ❌ API secrets or keys
- ❌ Database credentials
- ❌ Private tokens
- ❌ Encryption keys
- ❌ Any sensitive information
Safe to store in NEXT_PUBLIC_* variables:
- ✅ Public API endpoints (e.g.,
NEXT_PUBLIC_API_HOST) - ✅ Public feature flags
- ✅ Analytics IDs (for public services)
- ✅ Environment names (development, staging, production)
.env.sample:
# Backend API host URL
NEXT_PUBLIC_API_HOST=https://api.example.com # ← Must be HTTPS in productionRecommendation:
- Use
session-tokenheader exclusively for user authentication - If API-level authentication is needed, handle it server-side only
Before deploying to production, ensure:
- HTTPS/TLS enabled with valid certificate
- Password hashing with Argon2id or bcrypt (cost ≥ 12)
- Unique salts per user password
- Rate limiting on authentication endpoints
- Session token expiration implemented
- Account lockout after failed attempts
- Security logging enabled
- HSTS header configured
- CORS properly configured
- SQL injection prevention (use parameterized queries)
- Input validation on all endpoints
-
NEXT_PUBLIC_API_HOSTuses HTTPS URL - CSP headers configured
- No sensitive data in localStorage
- XSS prevention measures in place
- Error messages don't leak sensitive information
- All dependencies up to date
- Security audit completed
- Firewall rules configured
- Database access restricted
- Regular security patches applied
- Backup and disaster recovery plan
- Monitoring and alerting configured
- Security incident response plan
Before Committing Code:
- No hardcoded passwords or secrets
- All user inputs are validated
- No SQL injection vulnerabilities
- XSS prevention in place
- Authentication checks present
- Error handling doesn't leak info
Before Deploying:
- Environment variables properly set
- HTTPS enforced
- Security headers configured
- Dependencies scanned for vulnerabilities
- Security documentation updated
Production Environment:
- TLS/SSL certificates valid and up to date
- Firewall rules reviewed
- Database encrypted at rest
- Backups tested and verified
- Monitoring alerts configured
- Log aggregation enabled
If you discover a security vulnerability:
- DO NOT open a public GitHub issue
- Email security concerns to: [Your Security Email]
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if available)
- OWASP Top 10
- OWASP Authentication Cheat Sheet
- OWASP Password Storage Cheat Sheet
- Next.js Security Best Practices
Last Updated: 2026-01-25
Version: 1.0.0