nordabiz/docs/architecture/flows/01-authentication-flow.md
Maciej Pienczyn cebe52f303 refactor: Rebranding i aktualizacja modelu AI
- Zmiana nazwy: "Norda Biznes Hub" → "Norda Biznes Partner"
- Aktualizacja modelu AI: Gemini 2.0 Flash → Gemini 3 Flash
- Zachowano historyczne odniesienia w timeline i dokumentacji

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 14:08:39 +01:00

26 KiB

Authentication Flow

Document Version: 1.0 Last Updated: 2026-01-10 Status: Production LIVE Flow Type: User Authentication & Session Management


Overview

This document describes the complete authentication flow for the Norda Biznes Partner application, covering:

  • User Registration with email verification
  • Login with session management
  • Email Verification process
  • Password Reset flow
  • Session Management and cookies
  • Authorization Levels and access control

Key Technology:

  • Authentication Framework: Flask-Login
  • Password Hashing: PBKDF2:SHA256 (werkzeug.security)
  • Session Storage: Server-side session cookies
  • Email Delivery: Microsoft Graph API (OAuth 2.0)
  • CSRF Protection: Flask-WTF

Security Features:

  • Email verification required before login
  • Secure session cookies (HttpOnly, Secure, SameSite=Lax)
  • CSRF protection on all forms
  • Password strength requirements
  • Input sanitization against XSS
  • Rate limiting on authentication endpoints

1. User Registration Flow

1.1 Registration Sequence Diagram

sequenceDiagram
    actor User
    participant Browser
    participant Flask as Flask App<br/>(app.py)
    participant DB as PostgreSQL<br/>(users table)
    participant EmailSvc as Email Service<br/>(email_service.py)
    participant MSGraph as Microsoft Graph API

    User->>Browser: Navigate to /register
    Browser->>Flask: GET /register
    Flask->>Browser: Render register.html

    User->>Browser: Fill form (email, password, name, company_nip)
    Browser->>Flask: POST /register

    Note over Flask: CSRF token validated (automatic)
    Note over Flask: Input sanitization

    Flask->>Flask: validate_email(email)
    Flask->>Flask: validate_password(password)<br/>(8+ chars, uppercase, lowercase, digit)
    Flask->>Flask: validate NIP format (10 digits)

    Flask->>DB: SELECT * FROM users WHERE email = ?
    DB->>Flask: Check if exists

    alt Email already exists
        Flask->>Browser: Flash "Email już jest zarejestrowany"
        Browser->>User: Show error message
    else Email available
        Flask->>DB: SELECT * FROM companies WHERE nip = ? AND status = 'active'
        DB->>Flask: Company data (if NORDA member)

        Flask->>Flask: generate_password_hash(password)<br/>(PBKDF2:SHA256)
        Flask->>Flask: secrets.token_urlsafe(32)<br/>(verification token)
        Flask->>Flask: Calculate token expiry<br/>(now + 24 hours)

        Flask->>DB: INSERT INTO users<br/>(email, password_hash, name,<br/>verification_token, is_verified=FALSE,<br/>company_id, is_norda_member)
        DB->>Flask: User created (id)

        Flask->>EmailSvc: send_verification_email(email, token)
        EmailSvc->>MSGraph: POST /users/noreply@nordabiznes.pl/sendMail<br/>(OAuth 2.0 + Bearer token)
        MSGraph->>EmailSvc: 202 Accepted

        Flask->>Browser: Flash "Sprawdź email"<br/>Redirect to /login
        Browser->>User: Show success message
    end

1.2 Registration Implementation Details

Route: POST /register File: app.py (lines ~3077-3183) Rate Limit: 5 requests per hour per IP

Input Fields:

  • email (required, max 255 chars)
  • password (required, 8+ chars with complexity requirements)
  • name (required, max 255 chars)
  • company_nip (required, 10 digits)

Validation Steps:

  1. Email validation: Regex pattern check
  2. Password validation:
    • Minimum 8 characters
    • At least 1 uppercase letter
    • At least 1 lowercase letter
    • At least 1 digit
  3. NIP validation: Must be exactly 10 digits
  4. Company membership check: NIP lookup in companies table

Database Operations:

-- Check email uniqueness
SELECT * FROM users WHERE email = ?;

-- Verify company membership
SELECT * FROM companies WHERE nip = ? AND status = 'active';

-- Create user account
INSERT INTO users (
    email, password_hash, name, company_nip,
    verification_token, verification_token_expires,
    is_verified, is_norda_member, company_id,
    created_at
) VALUES (?, ?, ?, ?, ?, ?, FALSE, ?, ?, NOW());

Security Measures:

  • CSRF Protection: Automatic via Flask-WTF
  • Input Sanitization: sanitize_input() strips HTML/malicious patterns
  • Password Hashing: PBKDF2:SHA256 (werkzeug default)
  • Rate Limiting: 5 attempts/hour via Flask-Limiter
  • XSS Prevention: All user inputs sanitized

Email Verification Token:

  • Generated via secrets.token_urlsafe(32) (256-bit entropy)
  • Stored in users.verification_token column
  • Expires after 24 hours
  • Single-use (cleared after verification)

2. Email Verification Flow

2.1 Email Verification Sequence Diagram

sequenceDiagram
    actor User
    participant Email as Email Client
    participant Browser
    participant Flask as Flask App<br/>(app.py)
    participant DB as PostgreSQL

    Note over User,Email: User receives verification email

    User->>Email: Open verification email
    Email->>Browser: Click link:<br/>https://nordabiznes.pl/verify-email/<token>

    Browser->>Flask: GET /verify-email/<token>

    Flask->>Flask: Extract token from URL
    Flask->>DB: SELECT * FROM users<br/>WHERE verification_token = ?<br/>AND verification_token_expires > NOW()<br/>AND is_active = TRUE

    alt Token valid and not expired
        DB->>Flask: User found

        alt User already verified
            Flask->>Browser: Flash "Email został już zweryfikowany"<br/>Redirect to /login
        else User not verified yet
            Flask->>DB: UPDATE users SET<br/>is_verified = TRUE,<br/>verified_at = NOW(),<br/>verification_token = NULL,<br/>verification_token_expires = NULL<br/>WHERE id = ?

            DB->>Flask: Update successful

            Flask->>Browser: Flash "Email zweryfikowany!<br/>Możesz się teraz zalogować"<br/>Redirect to /login
            Browser->>User: Show success message
        end

    else Token invalid or expired
        Flask->>Browser: Flash "Link weryfikacyjny<br/>jest nieprawidłowy lub wygasł"<br/>Redirect to /login
        Browser->>User: Show error message
    end

2.2 Email Verification Implementation Details

Route: GET /verify-email/<token> File: app.py (lines ~3369-3405) Rate Limit: None (public endpoint)

Verification Logic:

# Query user by token
user = db.query(User).filter(
    User.verification_token == token,
    User.verification_token_expires > datetime.now(),
    User.is_active == True
).first()

if user and not user.is_verified:
    user.is_verified = True
    user.verified_at = datetime.now()
    user.verification_token = None
    user.verification_token_expires = None
    db.commit()

Token Expiry:

  • Verification tokens expire after 24 hours
  • Expired tokens cannot be used
  • Users can request new verification email via /resend-verification

Database Schema (users table):

verification_token VARCHAR(255) NULL
verification_token_expires TIMESTAMP NULL
is_verified BOOLEAN DEFAULT FALSE
verified_at TIMESTAMP NULL

3. Login Flow

3.1 Login Sequence Diagram

sequenceDiagram
    actor User
    participant Browser
    participant Flask as Flask App<br/>(app.py)
    participant FlaskLogin as Flask-Login
    participant DB as PostgreSQL
    participant Session as Session Cookie

    User->>Browser: Navigate to /login
    Browser->>Flask: GET /login
    Flask->>Browser: Render login.html with CSRF token

    User->>Browser: Enter email & password<br/>(optional: remember me)
    Browser->>Flask: POST /login<br/>(email, password, remember, csrf_token)

    Note over Flask: CSRF token validated

    Flask->>DB: SELECT * FROM users WHERE email = ?

    alt User not found
        DB->>Flask: No user
        Flask->>Browser: Flash "Nieprawidłowy email lub hasło"
        Browser->>User: Show error
    else User found
        DB->>Flask: User data

        Flask->>Flask: check_password_hash(<br/>user.password_hash,<br/>password<br/>)

        alt Password invalid
            Flask->>Browser: Flash "Nieprawidłowy email lub hasło"
            Browser->>User: Show error
        else Password valid
            alt User not active
                Flask->>Browser: Flash "Konto zostało dezaktywowane"
                Browser->>User: Show error
            else User not verified
                Flask->>Browser: Flash "Musisz potwierdzić adres email"
                Browser->>User: Show error with resend link
            else User active and verified
                Flask->>FlaskLogin: login_user(user, remember=remember)
                FlaskLogin->>Session: Set session cookie<br/>(secure, httponly, samesite=Lax)
                Session->>Browser: Store session cookie

                Flask->>DB: UPDATE users SET last_login = NOW() WHERE id = ?
                DB->>Flask: Update successful

                Flask->>Browser: Redirect to /dashboard<br/>(or 'next' URL if specified)
                Browser->>User: Show dashboard
            end
        end
    end

3.2 Login Implementation Details

Route: POST /login File: app.py (lines ~3184-3240) Rate Limit:

  • Development: 1000 requests per hour
  • Production: 5 requests per hour per IP

Login Validation Steps:

  1. Check email exists in database
  2. Verify password hash matches
  3. Check is_active = TRUE
  4. Require is_verified = TRUE
  5. Create session via Flask-Login
  6. Update last_login timestamp

Session Configuration:

# app.py session settings (lines ~161-168)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
app.config['SESSION_COOKIE_SECURE'] = True  # HTTPS only in production
app.config['SESSION_COOKIE_HTTPONLY'] = True  # No JS access
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'  # CSRF protection

Flask-Login Configuration:

# app.py Flask-Login setup (lines ~192-196)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
login_manager.login_message = 'Zaloguj się, aby uzyskać dostęp do tej strony.'

User Loader Function:

@login_manager.user_loader
def load_user(user_id):
    """Load user from database for Flask-Login"""
    db = SessionLocal()
    try:
        return db.query(User).get(int(user_id))
    except:
        return None
    finally:
        db.close()

Remember Me Functionality:

  • When enabled: Session cookie persists for 7 days
  • When disabled: Session cookie expires when browser closes
  • Implemented via Flask-Login's login_user(user, remember=True/False)

Next URL Redirect:

# Prevent open redirect vulnerability
next_page = request.args.get('next')
if next_page and not next_page.startswith('/'):
    next_page = None
return redirect(next_page or url_for('dashboard'))

4. Session Management

4.1 Session Lifecycle

stateDiagram-v2
    [*] --> Anonymous: User visits site
    Anonymous --> Authenticated: Successful login
    Authenticated --> Authenticated: Normal activity
    Authenticated --> Anonymous: Logout
    Authenticated --> Anonymous: Session expires (7 days)
    Authenticated --> Anonymous: User deactivated
    Anonymous --> [*]

Cookie Name: session (Flask default) Storage: Server-side (encrypted session data) Attributes:

  • Secure = True (HTTPS only in production)
  • HttpOnly = True (prevents XSS cookie theft)
  • SameSite = Lax (CSRF protection)
  • Max-Age = 7 days (with remember me)

Session Data Stored:

  • User ID (for user loader)
  • CSRF token (automatic via Flask-WTF)
  • Login timestamp
  • Remember me flag

Session Security:

  • Session cookie is signed with SECRET_KEY
  • Session data is encrypted (Flask built-in)
  • Session is regenerated on login (prevents session fixation)
  • Session is cleared on logout

5. Logout Flow

5.1 Logout Sequence Diagram

sequenceDiagram
    actor User
    participant Browser
    participant Flask as Flask App
    participant FlaskLogin as Flask-Login
    participant Session as Session Cookie

    User->>Browser: Click "Wyloguj" button
    Browser->>Flask: GET /logout

    Note over Flask: @login_required decorator<br/>verifies user is authenticated

    Flask->>FlaskLogin: logout_user()
    FlaskLogin->>Session: Clear session data
    Session->>Browser: Delete session cookie

    Flask->>Browser: Flash "Wylogowano pomyślnie"<br/>Redirect to /
    Browser->>User: Show homepage (logged out)

5.2 Logout Implementation Details

Route: GET /logout File: app.py (lines ~3242-3248) Authentication: Required (@login_required)

Implementation:

@app.route('/logout')
@login_required
def logout():
    """User logout"""
    logout_user()  # Flask-Login clears session
    flash('Wylogowano pomyślnie.', 'success')
    return redirect(url_for('index'))

What Happens on Logout:

  1. Flask-Login calls logout_user()
  2. Session cookie is deleted
  3. User object is removed from current_user
  4. Browser redirected to homepage
  5. All subsequent requests are anonymous

6. Password Reset Flow

6.1 Password Reset Sequence Diagram

sequenceDiagram
    actor User
    participant Browser
    participant Flask as Flask App
    participant DB as PostgreSQL
    participant EmailSvc as Email Service
    participant MSGraph as Microsoft Graph API

    Note over User,Browser: Phase 1: Request Reset

    User->>Browser: Navigate to /forgot-password
    Browser->>Flask: GET /forgot-password
    Flask->>Browser: Render forgot_password.html

    User->>Browser: Enter email address
    Browser->>Flask: POST /forgot-password (email)

    Flask->>Flask: validate_email(email)
    Flask->>DB: SELECT * FROM users<br/>WHERE email = ? AND is_active = TRUE

    alt User found
        DB->>Flask: User data

        Flask->>Flask: secrets.token_urlsafe(32)<br/>(generate reset token)
        Flask->>Flask: Calculate expiry (now + 1 hour)

        Flask->>DB: UPDATE users SET<br/>reset_token = ?,<br/>reset_token_expires = ?<br/>WHERE email = ?
        DB->>Flask: Update successful

        Flask->>EmailSvc: send_password_reset_email(email, token)
        EmailSvc->>MSGraph: POST /users/noreply@nordabiznes.pl/sendMail
        MSGraph->>EmailSvc: 202 Accepted

        Flask->>Browser: Flash "Sprawdź email"<br/>Redirect to /login
        Browser->>User: Show message

    else User not found
        Note over Flask: Still show success message<br/>(prevent email enumeration)
        Flask->>Browser: Flash "Sprawdź email"<br/>Redirect to /login
        Browser->>User: Show message
    end

    Note over User,Browser: Phase 2: Reset Password

    User->>Browser: Click link in email:<br/>https://nordabiznes.pl/reset-password/<token>
    Browser->>Flask: GET /reset-password/<token>

    Flask->>DB: SELECT * FROM users<br/>WHERE reset_token = ?<br/>AND reset_token_expires > NOW()

    alt Token valid
        DB->>Flask: User found
        Flask->>Browser: Render reset_password.html<br/>(password form)

        User->>Browser: Enter new password (twice)
        Browser->>Flask: POST /reset-password/<token><br/>(new_password, confirm_password)

        Flask->>Flask: validate_password(new_password)
        Flask->>Flask: Check passwords match
        Flask->>Flask: generate_password_hash(new_password)

        Flask->>DB: UPDATE users SET<br/>password_hash = ?,<br/>reset_token = NULL,<br/>reset_token_expires = NULL<br/>WHERE reset_token = ?
        DB->>Flask: Update successful

        Flask->>Browser: Flash "Hasło zostało zmienione"<br/>Redirect to /login
        Browser->>User: Show success message

    else Token invalid or expired
        Flask->>Browser: Flash "Link resetowania<br/>jest nieprawidłowy lub wygasł"<br/>Redirect to /forgot-password
        Browser->>User: Show error
    end

6.2 Password Reset Implementation Details

Routes:

  • POST /forgot-password - Request reset
  • GET /reset-password/<token> - Show reset form
  • POST /reset-password/<token> - Process new password

Files: app.py (lines ~3251-3368) Rate Limit: 5 requests per hour per IP

Reset Token Properties:

  • Generated via secrets.token_urlsafe(32) (256-bit entropy)
  • Expires after 1 hour
  • Single-use (cleared after successful reset)
  • Stored in users.reset_token column

Database Schema:

reset_token VARCHAR(255) NULL
reset_token_expires TIMESTAMP NULL

Security Considerations:

  • Reset tokens expire after 1 hour
  • Tokens are cleared after use
  • Password strength validation applied
  • Email enumeration prevented (always show success message)
  • Rate limiting prevents brute force

7. Authorization & Access Control

7.1 Authorization Levels

graph TB
    subgraph "Authorization Hierarchy"
        Public[👥 Public<br/>Anonymous Users]
        Auth[🔐 Authenticated<br/>Logged-in Users]
        Member[👔 NORDA Members<br/>is_norda_member=TRUE]
        Admin[👨‍💼 Administrators<br/>is_admin=TRUE]

        Public --> Auth
        Auth --> Member
        Member --> Admin
    end

    subgraph "Access Permissions"
        PublicRoutes["Public Routes:<br/>/, /search, /company/*,<br/>/audit/*, /api/companies"]
        AuthRoutes["Authenticated Routes:<br/>/dashboard, /chat,<br/>/forum/*, /wiadomosci/*,<br/>/kalendarz/*, /tablica/*"]
        AdminRoutes["Admin Routes:<br/>/admin/*, /api/*/audit"]
    end

    Public --> PublicRoutes
    Auth --> AuthRoutes
    Admin --> AdminRoutes

7.2 Route Protection Decorators

Public Access (No decorator):

@app.route('/')
def index():
    """Public company directory"""
    # No authentication required
    return render_template('index.html')

Authenticated Users Only:

@app.route('/dashboard')
@login_required
def dashboard():
    """User dashboard - requires login"""
    # current_user is automatically available
    return render_template('dashboard.html', user=current_user)

Admin Only (Custom check):

@app.route('/admin/users')
@login_required
def admin_users():
    """Admin user management"""
    if not current_user.is_admin:
        flash('Brak uprawnień administratora.', 'error')
        return redirect(url_for('index'))

    # Admin logic here
    return render_template('admin/users.html')

7.3 Access Control Matrix

Route Category Public Authenticated NORDA Member Admin
/ (Company directory)
/search
/company/<slug>
/audit/*/<slug>
/api/companies
/register, /login
/dashboard
/chat
/forum/*
/wiadomosci/*
/kalendarz/*
/tablica/*
/admin/*
/api/*/audit

Legend:

  • Access granted
  • Access denied (redirect to login or show error)

8. User Model Database Schema

8.1 Users Table Structure

CREATE TABLE users (
    -- Primary Key
    id SERIAL PRIMARY KEY,

    -- Authentication
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,

    -- Profile
    name VARCHAR(255),
    phone VARCHAR(50),

    -- Company Association
    company_nip VARCHAR(10),
    company_id INTEGER REFERENCES companies(id),

    -- Status Flags
    is_active BOOLEAN DEFAULT TRUE,
    is_verified BOOLEAN DEFAULT FALSE,
    is_admin BOOLEAN DEFAULT FALSE,
    is_norda_member BOOLEAN DEFAULT FALSE,

    -- Timestamps
    created_at TIMESTAMP DEFAULT NOW(),
    last_login TIMESTAMP,
    verified_at TIMESTAMP,

    -- Email Verification
    verification_token VARCHAR(255),
    verification_token_expires TIMESTAMP,

    -- Password Reset
    reset_token VARCHAR(255),
    reset_token_expires TIMESTAMP,

    -- Indexes
    INDEX idx_users_email (email),
    INDEX idx_users_company_id (company_id)
);

8.2 User Model (SQLAlchemy)

File: database.py (lines ~119-158)

class User(Base, UserMixin):
    """User accounts with Flask-Login integration"""
    __tablename__ = 'users'

    # Authentication fields
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False, index=True)
    password_hash = Column(String(255), nullable=False)

    # Profile
    name = Column(String(255))
    company_nip = Column(String(10))
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=True)
    phone = Column(String(50))

    # Status
    is_active = Column(Boolean, default=True)
    is_verified = Column(Boolean, default=False)
    is_admin = Column(Boolean, default=False)
    is_norda_member = Column(Boolean, default=False)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    last_login = Column(DateTime)
    verified_at = Column(DateTime)

    # Verification token
    verification_token = Column(String(255))
    verification_token_expires = Column(DateTime)

    # Password reset token
    reset_token = Column(String(255))
    reset_token_expires = Column(DateTime)

    # Relationships
    company = relationship('Company', backref='users', lazy='joined')
    conversations = relationship('AIChatConversation', back_populates='user')
    forum_topics = relationship('ForumTopic', back_populates='author')
    forum_replies = relationship('ForumReply', back_populates='author')

UserMixin Methods (Flask-Login):

  • is_authenticated - Always True for logged-in users
  • is_active - Returns self.is_active
  • is_anonymous - Always False for logged-in users
  • get_id() - Returns str(self.id) for session storage

9. Security Features Summary

9.1 Security Measures Implemented

Feature Implementation Protection Against
CSRF Protection Flask-WTF automatic tokens Cross-Site Request Forgery
Password Hashing PBKDF2:SHA256 (werkzeug) Rainbow table attacks
Secure Cookies HttpOnly, Secure, SameSite=Lax XSS cookie theft, CSRF
Email Verification Required before login Fake accounts
Input Sanitization sanitize_input() function XSS attacks
Rate Limiting Flask-Limiter (5 req/hour) Brute force attacks
Session Regeneration Flask-Login automatic Session fixation
Token Expiry 24h (verify), 1h (reset) Token replay attacks
Open Redirect Prevention Next URL validation Phishing attacks
Password Strength 8+ chars, complexity rules Weak passwords

9.2 Security Best Practices

Implemented: HTTPS enforced in production Password hashing with secure algorithm CSRF protection on all forms Session cookies with security flags Email verification required Rate limiting on auth endpoints Input sanitization Token expiry Open redirect prevention

Potential Improvements: ⚠️ Add account lockout after N failed attempts ⚠️ Implement 2FA (TOTP) for admins ⚠️ Add password history (prevent reuse) ⚠️ Log authentication events for auditing ⚠️ Add CAPTCHA on registration ⚠️ Implement session timeout (idle) ⚠️ Add IP-based rate limiting


10. Testing Accounts (Production)

10.1 Test Users

IMPORTANT: Use only these accounts for testing production features.

Account Email Role Purpose
Test User test@nordabiznes.pl Regular User Test user-level features
Test Admin testadmin@nordabiznes.pl Administrator Test admin features

Test Account Credentials:

  • Password stored in CLAUDE.md (do not commit to repository)
  • Accounts are pre-verified (is_verified = TRUE)
  • Test Admin has is_admin = TRUE flag

Usage:

  • Always use test accounts for production testing
  • Never modify real user accounts for testing
  • Test authentication flows, authorization, session management

11.1 Architecture Documents

11.2 Code Files

Authentication Routes:

  • app.py lines ~3077-3500 (register, login, logout, verify, reset)

User Model:

  • database.py lines ~119-158 (User model with Flask-Login)

Email Service:

  • email_service.py (Microsoft Graph email sending)

Security Utilities:

  • app.py - sanitize_input(), validate_email(), validate_password()

11.3 External Dependencies

  • Flask-Login: User session management
  • Flask-WTF: CSRF protection
  • Flask-Limiter: Rate limiting
  • werkzeug.security: Password hashing
  • secrets: Cryptographic token generation

12. Maintenance & Updates

12.1 When to Update This Document

Update this document when:

  • Authentication flow changes (new steps, validation)
  • Session management changes (cookie settings, expiry)
  • Security measures are added/modified
  • New authorization levels are introduced
  • User model schema changes

12.2 Verification Checklist

When updating authentication flow:

  • Test registration with valid/invalid data
  • Test email verification with valid/expired tokens
  • Test login with correct/incorrect credentials
  • Test session persistence (remember me)
  • Test logout clears session
  • Test password reset flow end-to-end
  • Verify CSRF protection is active
  • Verify rate limiting works
  • Test authorization levels (public, user, admin)
  • Verify security headers on cookies

12.3 Security Audit Checklist

Periodic security audit:

  • Review password hashing algorithm (current: PBKDF2:SHA256)
  • Check token expiry times (verify: 24h, reset: 1h)
  • Verify session cookie security flags
  • Review rate limiting thresholds
  • Check for SQL injection vulnerabilities
  • Test XSS prevention in inputs
  • Verify CSRF protection coverage
  • Review authentication logs for anomalies
  • Test open redirect prevention
  • Verify email verification enforcement

Document End

This document is maintained as part of the Norda Biznes Partner architecture documentation. For questions or updates, contact the development team.