# Backend Auth Module Documentation ## Overview The Auth module provides comprehensive authentication and authorization for the application. It supports local email/password authentication, OAuth 2.0 (Google, Microsoft), JWT-based session management, email verification, and password reset flows. **Files:** | File | Purpose | |------|---------| | `src/auth/auth.ts` | Passport.js strategy configurations (JWT, Google, Microsoft) | | `src/services/auth.ts` | Auth business logic (signin, password reset/update, email verification) | | `src/routes/auth.ts` | REST API endpoints for authentication | | `src/helpers.ts` | JWT signing utility (`jwtSign`) | | `src/db/api/users.js` | User database operations (tokens, password updates) | | `src/middlewares/rateLimiter.js` | Auth-specific rate limiters | --- ## Architecture Diagram ``` ┌──────────────────────────────────────────────────────────────────────┐ │ Frontend/Client │ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────────────┐ │ │ │ Login Form │ │ Signup Form │ │ OAuth Buttons │ │ │ │ (email/pass) │ │ (email/pass) │ │ (Google/Microsoft) │ │ │ └───────┬────────┘ └───────┬────────┘ └───────────┬────────────┘ │ └──────────┼───────────────────┼───────────────────────┼───────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Routes Layer (routes/auth.ts) │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ Rate Limiters: │ │ │ │ • authLimiter (10 req/15min) → /signin/local │ │ │ │ • passwordResetLimiter (5 req/hour) → /send-password-reset │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────────────┐ │ │ │ POST /signin │ │ PUT /reset │ │ GET /signin/google │ │ │ │ /local │ │ │ │ GET /signin/microsoft │ │ │ └───────┬───────┘ └───────┬───────┘ └───────────┬───────────┘ │ │ │ │ │ │ └──────────┼──────────────────┼──────────────────────┼─────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Service Layer (services/auth.ts) │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ Auth Class (Static Methods) │ │ │ │ • signup(email, password, options, host) │ │ │ │ • signin(email, password) │ │ │ │ • verifyEmail(token) │ │ │ │ • passwordUpdate(currentPassword, newPassword, options) │ │ │ │ • passwordReset(token, password) │ │ │ │ • sendEmailAddressVerificationEmail(email, host) │ │ │ │ • sendPasswordResetEmail(email, type, host) │ │ │ │ • updateProfile(data, currentUser) │ │ │ └────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Passport Layer (auth/auth.ts) │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │ │ JWT Strategy │ │ Google Strategy │ │ Microsoft Strategy │ │ │ │ (API Auth) │ │ (OAuth 2.0) │ │ (OAuth 2.0) │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │ │ │ │ │ └──────────┬───────────┘ │ │ │ │ │ ┌──────────▼──────────┐ │ │ │ socialStrategy() │ │ │ │ • findOrCreate │ │ │ │ • Generate JWT │ │ │ └─────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Database Layer (db/api/users.js) │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ UsersDBApi (Static Methods) │ │ │ │ • findBy({ email }) │ │ │ │ • createFromAuth(data) │ │ │ │ • updatePassword(id, password) │ │ │ │ • generateEmailVerificationToken(email) │ │ │ │ • generatePasswordResetToken(email) │ │ │ │ • findByEmailVerificationToken(token) │ │ │ │ • findByPasswordResetToken(token) │ │ │ │ • markEmailVerified(id) │ │ │ └────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘ ``` --- ## Authentication Strategies ### 1. JWT Strategy (Primary) Used for API authentication on all protected routes. **Configuration (auth/auth.ts):** ```javascript passport.use( new JWTstrategy({ passReqToCallback: true, secretOrKey: config.secret_key, jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(), }, async (req, token, done) => { const user = await UsersDBApi.findBy({ email: token.user.email }); if (user && user.disabled) { return done(new Error(`User '${user.email}' is disabled`)); } req.currentUser = user; return done(null, user); }) ); ``` **Token Structure:** ```javascript { user: { id: "uuid", email: "user@example.com" }, iat: 1234567890, // Issued at exp: 1234589490 // Expires in 6 hours } ``` **Usage:** ```javascript // Protect route with JWT router.get('/me', passport.authenticate('jwt', { session: false }), handler); // Access user in handler const currentUser = req.currentUser; ``` ### 2. Google OAuth Strategy **Configuration (auth/auth.ts):** ```javascript passport.use( new GoogleStrategy({ clientID: config.google.clientId, clientSecret: config.google.clientSecret, callbackURL: config.apiUrl + '/auth/signin/google/callback', passReqToCallback: true, }, (request, accessToken, refreshToken, profile, done) => { socialStrategy(profile.email, profile, providers.GOOGLE, done); }) ); ``` **Environment Variables:** | Variable | Description | |----------|-------------| | `GOOGLE_CLIENT_ID` | Google OAuth client ID | | `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | **OAuth Scopes:** `profile`, `email` ### 3. Microsoft OAuth Strategy **Configuration (auth/auth.ts):** ```javascript passport.use( new MicrosoftStrategy({ clientID: config.microsoft.clientId, clientSecret: config.microsoft.clientSecret, callbackURL: config.apiUrl + '/auth/signin/microsoft/callback', passReqToCallback: true, }, (request, accessToken, refreshToken, profile, done) => { const email = profile._json.mail || profile._json.userPrincipalName; socialStrategy(email, profile, providers.MICROSOFT, done); }) ); ``` **Environment Variables:** | Variable | Description | |----------|-------------| | `MS_CLIENT_ID` | Microsoft OAuth client ID | | `MS_CLIENT_SECRET` | Microsoft OAuth client secret | **OAuth Scopes:** `https://graph.microsoft.com/user.read`, `openid` ### Social Strategy Helper Common logic for OAuth providers: ```javascript function socialStrategy(email, profile, provider, done) { db.users.findOrCreate({ where: { email, provider } }).then(([user]) => { const body = { id: user.id, email: user.email, name: profile.displayName, }; const token = helpers.jwtSign({ user: body }); return done(null, { token }); }); } ``` --- ## File Details ### 1. services/auth.ts Core authentication business logic. #### Class: Auth ```typescript class Auth { static async signin(email, password) static async verifyEmail(token, options) static async passwordUpdate(currentPassword, newPassword, options) static async passwordReset(token, password, options) static async sendEmailAddressVerificationEmail(email, host) static async sendPasswordResetEmail(email, type, host) static async updateProfile(data, currentUser) } ``` #### Method: signup(email, password, options, host) Registers a new user or updates password for existing unverified user. **Flow:** ``` 1. Check if user exists by email ├── User exists with authenticationUid → Error: emailAlreadyInUse ├── User exists but disabled → Error: userDisabled └── User exists without authenticationUid → Update password 2. If new user: ├── Hash password (bcrypt, 12 rounds) ├── Create user via UsersDBApi.createFromAuth() └── Assign default "User" role 3. Send verification email (if EmailSender configured) 4. Return signed JWT token ``` **Returns:** JWT token string #### Method: signin(email, password) Authenticates user with email and password. **Flow:** ``` 1. Find user by email └── Not found → Error: userNotFound 2. Check if disabled └── Disabled → Error: userDisabled 3. Verify password exists └── No password → Error: wrongPassword 4. Check email verification └── Not verified (and email configured) → Error: userNotVerified 5. Compare password with bcrypt └── Mismatch → Error: wrongPassword 6. Return signed JWT token ``` **Returns:** JWT token string #### Method: verifyEmail(token, options) Verifies user email address using token. **Flow:** ``` 1. Find user by email verification token └── Not found or expired → Error: invalidToken 2. Mark email as verified 3. Return true ``` #### Method: passwordUpdate(currentPassword, newPassword, options) Updates password for authenticated user. **Flow:** ``` 1. Verify currentUser exists └── Not authenticated → ForbiddenError 2. Verify current password matches └── Mismatch → Error: wrongPassword 3. Verify new password is different └── Same → Error: samePassword 4. Hash new password and update ``` #### Method: passwordReset(token, password, options) Resets password using reset token. **Flow:** ``` 1. Find user by password reset token └── Not found or expired → Error: invalidToken 2. Hash new password 3. Update user password ``` --- ### 2. routes/auth.ts (327 lines) REST API endpoints for authentication. #### Endpoints Overview | Method | Path | Auth | Rate Limit | Description | |--------|------|------|------------|-------------| | POST | `/signin/local` | No | authLimiter | Login with email/password | | GET | `/me` | JWT | - | Get current user | | PUT | `/password-reset` | No | - | Reset password with token | | PUT | `/password-update` | JWT | - | Change password | | PUT | `/profile` | JWT | - | Update user profile | | PUT | `/verify-email` | No | - | Verify email with token | | POST | `/send-email-address-verification-email` | JWT | - | Resend verification email | | POST | `/send-password-reset-email` | No | passwordResetLimiter | Send password reset email | | GET | `/email-configured` | No | - | Check if email is configured | | GET | `/signin/google` | No | - | Initiate Google OAuth | | GET | `/signin/google/callback` | No | - | Google OAuth callback | | GET | `/signin/microsoft` | No | - | Initiate Microsoft OAuth | | GET | `/signin/microsoft/callback` | No | - | Microsoft OAuth callback | #### POST /api/auth/signin/local Login with email and password. **Request:** ```json { "email": "user@example.com", "password": "securepassword123" } ``` **Response (200):** ```json "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ``` **Errors:** | Code | Message | Cause | |------|---------|-------| | 400 | `auth.userNotFound` | User doesn't exist | | 400 | `auth.userDisabled` | User account is disabled | | 400 | `auth.wrongPassword` | Invalid password | | 400 | `auth.userNotVerified` | Email not verified | | 429 | Too Many Requests | Rate limit exceeded | #### Self-Registration Self-registration is disabled. `POST /api/auth/signup` is not registered. New users are created through the authenticated Users flow and receive an invitation/setup link. #### GET /api/auth/me Get current authenticated user. **Headers:** ``` Authorization: Bearer ``` **Response (200):** ```json { "id": "uuid", "email": "user@example.com", "firstName": "John", "lastName": "Doe", "emailVerified": true, "disabled": false, "app_role": { "id": "uuid", "name": "Administrator", "permissions": [...] }, "custom_permissions": [], "avatar": [...], "createdAt": "2024-01-01T00:00:00.000Z" } ``` **Note:** Password field is omitted from response. #### PUT /api/auth/password-reset Reset password using token from email. **Request:** ```json { "token": "abc123...", "password": "newSecurePassword456" } ``` **Response (200):** ```json { "success": true } ``` #### PUT /api/auth/password-update Change password for authenticated user. **Headers:** ``` Authorization: Bearer ``` **Request:** ```json { "currentPassword": "oldPassword123", "newPassword": "newPassword456" } ``` **Errors:** | Code | Message | Cause | |------|---------|-------| | 400 | `auth.wrongPassword` | Current password incorrect | | 400 | `auth.passwordUpdate.samePassword` | New password same as old | | 403 | Forbidden | Not authenticated | #### PUT /api/auth/profile Update user profile. **Headers:** ``` Authorization: Bearer ``` **Request:** ```json { "profile": { "firstName": "John", "lastName": "Smith", "phoneNumber": "+1234567890" } } ``` #### OAuth Endpoints **GET /api/auth/signin/google** - Redirects to Google OAuth consent screen - Query param: `app` (passed as state) **GET /api/auth/signin/google/callback** - Handles Google OAuth callback - Redirects to: `{uiUrl}/login?token={jwt}` **GET /api/auth/signin/microsoft** - Redirects to Microsoft OAuth consent screen - Query param: `app` (passed as state) **GET /api/auth/signin/microsoft/callback** - Handles Microsoft OAuth callback - Redirects to: `{uiUrl}/login?token={jwt}` --- ### 3. helpers.js (32 lines) JWT and utility functions. #### Method: jwtSign(data) Signs JWT token with application secret. ```javascript static jwtSign(data) { return jwt.sign(data, config.secret_key, { expiresIn: '6h' }); } ``` **Configuration:** | Setting | Value | Description | |---------|-------|-------------| | Secret Key | `config.secret_key` | From `SECRET_KEY` env var | | Expiration | `6h` | Token valid for 6 hours | | Algorithm | `HS256` | Default HMAC SHA-256 | --- ### 4. db/api/users.js (Authentication Methods) User database operations related to authentication. #### Method: createFromAuth(data) Creates new user during signup. ```javascript static async createFromAuth(data, options) { const users = await db.users.create({ email: data.email, firstName: data.firstName, authenticationUid: data.authenticationUid, password: data.password, }, { transaction }); // Assign default "User" role const app_role = await db.roles.findOne({ where: { name: config.roles?.user || 'User' }, }); await users.setApp_role(app_role?.id); return users; } ``` #### Method: generateEmailVerificationToken(email) Generates secure token for email verification. ```javascript static async generateEmailVerificationToken(email, options) { const token = crypto.randomBytes(20).toString('hex'); const tokenExpiresAt = Date.now() + (24 * 60 * 60 * 1000); // 24 hours await users.update({ emailVerificationToken: token, emailVerificationTokenExpiresAt: tokenExpiresAt, }); return token; } ``` **Token Properties:** | Property | Value | |----------|-------| | Length | 40 hex characters | | Expiry | 24 hours | | Storage | `emailVerificationToken` column | #### Method: generatePasswordResetToken(email) Generates secure token for password reset. Same implementation as `generateEmailVerificationToken` but stores in: - `passwordResetToken` - `passwordResetTokenExpiresAt` #### Method: findByEmailVerificationToken(token) Finds user by valid (non-expired) verification token. ```javascript static async findByEmailVerificationToken(token, options) { return db.users.findOne({ where: { emailVerificationToken: token, emailVerificationTokenExpiresAt: { [Op.gt]: Date.now(), }, }, }); } ``` #### Method: markEmailVerified(id) Marks user email as verified. ```javascript static async markEmailVerified(id, options) { const users = await db.users.findByPk(id); await users.update({ emailVerified: true }); return true; } ``` --- ## Rate Limiting Authentication endpoints have dedicated rate limiters defined in `middlewares/rateLimiter.js`. ### Auth Limiter (Login) ```javascript const authLimiter = createRateLimiter({ keyPrefix: 'auth', windowMs: 15 * 60 * 1000, // 15 minutes max: 10, message: 'Too many authentication attempts. Please try again later.', skipFailedRequests: false, // Count ALL attempts }); ``` | Setting | Value | |---------|-------| | Window | 15 minutes | | Max Requests | 10 | | Applied To | `/signin/local` | ### Signup Limiter Self-registration is disabled, so no signup limiter is registered. ### Password Reset Limiter ```javascript const passwordResetLimiter = createRateLimiter({ keyPrefix: 'password-reset', windowMs: 60 * 60 * 1000, // 1 hour max: 5, message: 'Too many password reset requests. Please try again later.', }); ``` | Setting | Value | |---------|-------| | Window | 1 hour | | Max Requests | 5 | | Applied To | `/send-password-reset-email` | ### Rate Limit Response ```json { "error": "Too Many Requests", "message": "Too many authentication attempts. Please try again later.", "retryAfter": 300 } ``` **Headers:** ``` X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 2024-01-01T00:15:00.000Z Retry-After: 300 ``` --- ## Password Security ### Hashing Configuration ```javascript // config.ts bcrypt: { saltRounds: 12, } ``` | Setting | Value | Security Impact | |---------|-------|-----------------| | Algorithm | bcrypt | Industry standard | | Salt Rounds | 12 | ~200ms hash time | | Salt | Auto-generated | Per-password unique | ### Password Validation Passwords are: 1. Hashed before storage (never stored in plain text) 2. Compared using `bcrypt.compare()` (timing-attack safe) 3. Required for local authentication --- ## Email Integration Email functionality is conditional based on configuration. ### Email Configuration Check ```javascript if (EmailSender.isConfigured) { await this.sendEmailAddressVerificationEmail(user.email, host); } ``` When email is NOT configured: - Signup succeeds without verification email - Users are auto-verified on signin - Password reset emails not sent ### Verification Email **Email Class:** `EmailAddressVerificationEmail` **Link Format:** ``` {host}/verify-email?token={token} ``` ### Password Reset Email **Email Classes:** - `PasswordResetEmail` - Standard reset - `InvitationEmail` - New user invitation **Link Format:** ``` {host}/password-reset?token={token} ``` --- ## Configuration Reference ### Environment Variables | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `SECRET_KEY` | Yes | `88dbeaf8-e906-405e-9e41-c3baadeda5c6` | JWT signing secret | | `GOOGLE_CLIENT_ID` | No | - | Google OAuth client ID | | `GOOGLE_CLIENT_SECRET` | No | - | Google OAuth client secret | | `MS_CLIENT_ID` | No | - | Microsoft OAuth client ID | | `MS_CLIENT_SECRET` | No | - | Microsoft OAuth client secret | | `ADMIN_EMAIL` | No | `admin@flatlogic.com` | Default admin email | | `ADMIN_PASS` | No | `88dbeaf8` | Default admin password | | `USER_PASS` | No | `c3baadeda5c6` | Default user password | ### config.ts Settings ```javascript { bcrypt: { saltRounds: 12 }, secret_key: env.SECRET_KEY, providers: { LOCAL: 'local', GOOGLE: 'google', MICROSOFT: 'microsoft', }, google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, microsoft: { clientId: env.MS_CLIENT_ID, clientSecret: env.MS_CLIENT_SECRET, }, roles: { admin: 'Administrator', user: 'Analytics Viewer', }, } ``` --- ## Authentication Flows ### Local Login Flow ``` ┌────────┐ ┌─────────┐ ┌─────────────┐ ┌──────────┐ │ Client │────▶│ Router │────▶│ AuthService │────▶│ UsersDB │ └────────┘ └─────────┘ └─────────────┘ └──────────┘ │ │ │ │ │ POST /signin │ │ │ │ {email,pass} │ │ │ │──────────────▶│ │ │ │ │ signin() │ │ │ │───────────────▶│ │ │ │ │ findBy({email}) │ │ │ │──────────────────▶│ │ │ │◀──────────────────│ │ │ │ │ │ │ │ bcrypt.compare() │ │ │ │ │ │ │ │ jwtSign() │ │ │◀───────────────│ │ │◀──────────────│ │ │ │ JWT Token │ │ │ ``` ### OAuth Login Flow ``` ┌────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ │ Client │ │ Backend │ │ Provider │ │ UsersDB │ └────────┘ └─────────┘ └──────────┘ └──────────┘ │ │ │ │ │ GET /signin/ │ │ │ │ google │ │ │ │──────────────▶│ │ │ │ │ Redirect to │ │ │◀──────────────│ consent screen │ │ │──────────────────────────────▶│ │ │ │ │ │ │ │ User consents │ │ │◀──────────────────────────────│ │ │ │ │ │ │ GET /callback │ │ │ │ ?code=... │ │ │ │──────────────▶│ │ │ │ │ Exchange code │ │ │ │───────────────▶│ │ │ │ Profile data │ │ │ │◀───────────────│ │ │ │ │ │ │ │ findOrCreate() │ │ │ │───────────────────────────────▶│ │ │◀───────────────────────────────│ │ │ jwtSign() │ │ │ │ │ │ │ Redirect to │ │ │ │ /login?token= │ │ │ │◀──────────────│ │ │ ``` ### Email Verification Flow ``` ┌────────┐ ┌─────────┐ ┌─────────────┐ ┌───────┐ │ Client │ │ Router │ │ AuthService │ │ Email │ └────────┘ └─────────┘ └─────────────┘ └───────┘ │ │ │ │ │ POST /signup │ │ │ │──────────────▶│ │ │ │ │ signup() │ │ │ │───────────────▶│ │ │ │ │ generateToken()│ │ │ │ sendEmail() │ │ │ │───────────────▶│ │ │◀───────────────│ │ │◀──────────────│ │ │ │ JWT Token │ │ │ │ │ │ │ │ User clicks email link │ │ │ │ │ │ │ PUT /verify- │ │ │ │ email │ │ │ │ {token} │ │ │ │──────────────▶│ │ │ │ │ verifyEmail() │ │ │ │───────────────▶│ │ │ │ │ markVerified() │ │ │◀───────────────│ │ │◀──────────────│ │ │ │ Success │ │ │ ``` --- ## Error Codes | Error Key | HTTP Status | Description | |-----------|-------------|-------------| | `auth.userNotFound` | 400 | User with email doesn't exist | | `auth.userDisabled` | 400 | User account is disabled | | `auth.wrongPassword` | 400 | Password doesn't match | | `auth.userNotVerified` | 400 | Email not verified | | `auth.emailAlreadyInUse` | 400 | Email already registered | | `auth.passwordUpdate.samePassword` | 400 | New password same as current | | `auth.passwordReset.error` | 400 | Token generation failed | | `auth.passwordReset.invalidToken` | 400 | Invalid or expired reset token | | `auth.emailAddressVerificationEmail.error` | 400 | Verification email failed | | `auth.emailAddressVerificationEmail.invalidToken` | 400 | Invalid verification token | --- ## Security Considerations 1. **Password Storage:** bcrypt with 12 salt rounds 2. **JWT Expiration:** 6 hours (balances security and UX) 3. **Token Generation:** crypto.randomBytes(20) - 160-bit entropy 4. **Token Expiry:** 24 hours for email/password reset tokens 5. **Rate Limiting:** Prevents brute force attacks 6. **Disabled User Check:** Checked on both JWT validation and login 7. **Session-less:** No server-side session storage (stateless JWT) 8. **HTTPS Required:** OAuth callbacks require HTTPS in production --- ## Testing ### Test Local Login ```bash curl -X POST http://localhost:3000/api/auth/signin/local \ -H "Content-Type: application/json" \ -d '{"email": "admin@flatlogic.com", "password": "password"}' ``` ### Test Get Current User ```bash curl http://localhost:3000/api/auth/me \ -H "Authorization: Bearer " ``` ### User Creation Use the authenticated Users API/UI to create invited users. ## Dependencies | Package | Version | Purpose | |---------|---------|---------| | `passport` | ^0.6.0 | Authentication middleware | | `passport-jwt` | ^4.0.0 | JWT strategy for Passport | | `passport-google-oauth2` | ^0.2.0 | Google OAuth strategy | | `passport-microsoft` | ^2.0.0 | Microsoft OAuth strategy | | `@types/passport-jwt` | ^4.0.1 | Maintained TypeScript definitions for JWT Passport strategy | | `@types/passport-google-oauth2` | ^0.1.10 | Maintained TypeScript definitions for Google OAuth Passport strategy | | `@types/passport-microsoft` | ^2.1.1 | Maintained TypeScript definitions for Microsoft Passport strategy | | `jsonwebtoken` | ^9.0.0 | JWT sign/verify | | `bcrypt` | ^5.1.0 | Password hashing | | `crypto` | built-in | Token generation | --- ## Summary The Auth module provides: 1. **JWT Authentication** - Stateless API authentication with 6-hour tokens 2. **Local Login** - Email/password authentication with bcrypt 3. **OAuth 2.0** - Google and Microsoft social login 4. **Email Verification** - Token-based email confirmation 5. **Password Reset** - Secure token-based password recovery 6. **Rate Limiting** - Protection against brute force attacks 7. **Profile Management** - User profile updates 8. **Role Assignment** - Default role on signup