This document provides complete documentation for the SOBIE Conference Platform authentication system, including JWT-based authentication, magic links, and session management.
The SOBIE authentication system provides:
Traditional login with email and password.
Passwordless authentication via secure links sent to email or SMS.
JWT tokens with automatic refresh and secure cookie storage.
/api/auth/register
Register a new user account.
Request Body:
{
"email": "user@example.com",
"password": "securePassword123",
"name": {
"firstName": "John",
"lastName": "Doe",
"prefix": "Dr.",
"pronouns": "he/him"
},
"userType": "academic",
"affiliation": {
"organization": "University of Technology",
"department": "Computer Science",
"jobTitle": "Professor"
},
"magicLinkEnabled": false
}
Response (201):
{
"success": true,
"message": "SOBIE Profile creation successful. Please check your email to verify your account.",
"data": {
"user": {
"_id": "user-id",
"email": "user@example.com",
"name": { "firstName": "John", "lastName": "Doe" },
"userType": "academic",
"roles": ["user"],
"isEmailVerified": false
},
"tokens": {
"accessToken": "jwt-access-token",
"refreshToken": "jwt-refresh-token",
"accessTokenExpiry": 1640995200000,
"refreshTokenExpiry": 1641600000000
},
"emailVerificationSent": true
}
}
/api/auth/login
Login with email and password.
Request Body:
{
"email": "user@example.com",
"password": "securePassword123"
}
Response (200):
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"_id": "user-id",
"email": "user@example.com",
"fullName": "Dr. John Doe",
"roles": ["user", "reviewer"],
"primaryRole": "reviewer",
"lastLogin": "2024-01-01T10:00:00.000Z"
},
"tokens": {
"accessToken": "jwt-access-token",
"refreshToken": "jwt-refresh-token",
"accessTokenExpiry": 1640995200000,
"refreshTokenExpiry": 1641600000000
}
}
}
/api/auth/magic-link
Request a magic link for passwordless login.
Request Body:
{
"email": "user@example.com",
"method": "email" // or "sms"
}
Response (200):
{
"success": true,
"message": "Magic link sent to your email",
"data": {
"method": "email",
"expiresIn": "10 minutes"
}
}
/api/auth/magic-login
Login using a magic link token.
Request Body:
{
"token": "magic-link-token-from-email"
}
Response (200):
{
"success": true,
"message": "Magic link login successful",
"data": {
"user": { /* user object */ },
"tokens": { /* JWT tokens */ }
}
}
/api/auth/refresh
Refresh an expired access token using refresh token.
Request Body:
{
"refreshToken": "jwt-refresh-token"
}
Note: Refresh token can also be sent via secure cookies
Response (200):
{
"success": true,
"message": "Token refreshed successfully",
"data": {
"accessToken": "new-jwt-access-token",
"accessTokenExpiry": 1640995200000
}
}
/api/auth/validate
Validate current session/token.
Headers:
Authorization: Bearer jwt-access-token
Response (200):
{
"success": true,
"valid": true,
"data": {
"user": { /* user object */ },
"tokenInfo": {
"expiresAt": 1640995200000,
"issuedAt": 1640994300000,
"timeUntilExpiry": 900000
}
}
}
/api/auth/verify-email
Verify email address with token from verification email.
Request Body:
{
"token": "email-verification-token"
}
Response (200):
{
"success": true,
"message": "Email verified successfully",
"data": {
"user": {
"_id": "user-id",
"email": "user@example.com",
"isEmailVerified": true
}
}
}
/api/auth/resend-verification
Resend email verification.
Request Body:
{
"email": "user@example.com"
}
Response (200):
{
"success": true,
"message": "Verification email sent"
}
/api/auth/forgot-password
Request password reset email.
Request Body:
{
"email": "user@example.com"
}
Response (200):
{
"success": true,
"message": "Password reset link sent to your email",
"data": {
"expiresIn": "10 minutes"
}
}
/api/auth/reset-password
Reset password using token from reset email.
Request Body:
{
"token": "password-reset-token",
"password": "newSecurePassword123"
}
Response (200):
{
"success": true,
"message": "Password reset successful"
}
/api/auth/change-password
Change password for authenticated user.
Headers:
Authorization: Bearer jwt-access-token
Request Body:
{
"currentPassword": "currentPassword123",
"newPassword": "newSecurePassword123"
}
Response (200):
{
"success": true,
"message": "Password changed successfully"
}
/api/auth/me
Get current user profile.
Headers:
Authorization: Bearer jwt-access-token
Response (200):
{
"success": true,
"data": {
"user": {
"_id": "user-id",
"email": "user@example.com",
"fullName": "Dr. John Doe",
"name": { /* complete name object */ },
"affiliation": { /* affiliation details */ },
"roles": ["user", "reviewer"],
"isEmailVerified": true,
"lastLogin": "2024-01-01T10:00:00.000Z"
}
}
}
/api/auth/logout
Logout current user.
Headers:
Authorization: Bearer jwt-access-token
Response (200):
{
"success": true,
"message": "Logged out successfully"
}
1. User registers via POST /api/auth/register
2. System sends email verification
3. User verifies email via POST /api/auth/verify-email
4. User logs in via POST /api/auth/login
5. System returns JWT tokens and sets secure cookies
6. Frontend stores tokens and redirects to dashboard
1. User requests magic link via POST /api/auth/magic-link
2. System sends email/SMS with magic link
3. User clicks link, frontend extracts token
4. Frontend calls POST /api/auth/magic-login with token
5. System returns JWT tokens and sets secure cookies
6. User is logged in automatically
1. Frontend detects expired access token
2. Frontend calls POST /api/auth/refresh with refresh token
3. System returns new access token
4. Frontend updates stored token and retries original request
{
"success": false,
"message": "Please provide email and password"
}
{
"success": false,
"message": "Invalid credentials",
"code": "INVALID_CREDENTIALS"
}
{
"success": false,
"message": "Access token has expired",
"code": "TOKEN_EXPIRED"
}
{
"success": false,
"message": "Account is temporarily locked due to security reasons",
"code": "ACCOUNT_LOCKED",
"lockUntil": "2024-01-01T12:00:00.000Z"
}
{
"success": false,
"message": "Email verification required",
"code": "EMAIL_NOT_VERIFIED",
"hint": "Please check your email and click the verification link."
}
{
"success": false,
"message": "Too many authentication attempts, please try again later.",
"retryAfter": 900
}
// 1. Check if user is authenticated
const checkAuth = async () => {
try {
const response = await fetch('/api/auth/validate', {
credentials: 'include' // Include cookies
});
const data = await response.json();
return data.valid;
} catch (error) {
return false;
}
};
// 2. Login with email/password
const login = async (email, password) => {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ email, password })
});
return response.json();
};
// 3. Request magic link
const requestMagicLink = async (email) => {
const response = await fetch('/api/auth/magic-link', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
return response.json();
};
// 4. Logout
const logout = async () => {
const response = await fetch('/api/auth/logout', {
method: 'POST',
credentials: 'include'
});
return response.json();
};
// Extract token from URL query parameter
const urlParams = new URLSearchParams(window.location.search);
const magicToken = urlParams.get('token');
if (magicToken) {
// Login with magic link token
const response = await fetch('/api/auth/magic-login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ token: magicToken })
});
if (response.ok) {
// Redirect to dashboard
window.location.href = '/dashboard';
}
}
// Axios interceptor for automatic token refresh
axios.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401 && error.response?.data?.code === 'TOKEN_EXPIRED') {
try {
// Try to refresh token
await fetch('/api/auth/refresh', {
method: 'POST',
credentials: 'include'
});
// Retry original request
return axios.request(error.config);
} catch (refreshError) {
// Refresh failed, redirect to login
window.location.href = '/login';
}
}
return Promise.reject(error);
}
);
Required environment variables for authentication:
# JWT Configuration
JWT_SECRET=your-64-byte-random-secret
JWT_REFRESH_SECRET=your-64-byte-refresh-secret
JWT_EXPIRE=15m
JWT_REFRESH_EXPIRE=7d
# Email Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
FROM_EMAIL=noreply@sobie.org
# Optional SMS Configuration
TWILIO_ACCOUNT_SID=your-twilio-sid
TWILIO_AUTH_TOKEN=your-twilio-token
TWILIO_PHONE_NUMBER=+1234567890
# Application URLs
FRONTEND_URL=http://localhost:3000
Generate secure secrets:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
This authentication system provides enterprise-grade security with user-friendly features like magic links and automatic session management. All endpoints are rate-limited and include comprehensive error handling for production use.