Skip to content

Instantly share code, notes, and snippets.

@abidkhan484
Last active December 23, 2025 11:24
Show Gist options
  • Select an option

  • Save abidkhan484/4e820bc26818d6866a1603d3ffe37d30 to your computer and use it in GitHub Desktop.

Select an option

Save abidkhan484/4e820bc26818d6866a1603d3ffe37d30 to your computer and use it in GitHub Desktop.
Authentication and Authorization

Authorization & Security Implementation Plan

Document Version: 1.0
Created: 2025-12-23


1. Executive Summary

This document outlines the implementation plan for adding Role-Based Access Control (RBAC) and Secure Authentication to MedStory. The goal is to create a secure, MVP-ready authentication system that allows patients to share their medical timeline with relatives and doctors via secure, time-limited access links.

Key Features (MVP Scope)

  • ✅ User registration (self-register + invitation-style via shared links)
  • ✅ Email verification with OTP option
  • ✅ Login with Email/Password + OAuth (Google)
  • ✅ JWT-based session management with refresh tokens
  • ✅ Password complexity rules & reset functionality
  • ✅ Two-Factor Authentication (2FA)
  • ✅ Session timeout & management
  • ✅ Shareable access links:
    • Authenticated links - Recipient must register/login to view
    • One-time public links - Single-use, no account required (for doctors)
  • ✅ Relative connections with delegated permissions (view + create links)
  • ✅ Revocable access permissions
  • ✅ Audit logging for data access
  • ✅ Alembic database migrations

2. User Model & Roles

2.1 Single Role: Patient

All users are Patients who own their medical timeline. There is no separate "relative" or "doctor" user type.

block-beta
    columns 1
    block:user["User (Patient)"]:1
        columns 1
        A["• Owns their medical timeline"]
        B["• Can connect with other users as 'relatives'"]
        C["• Can generate shareable access links"]
        D["• Can grant/revoke access to their data"]
    end
Loading

2.2 Relative Connections & Permissions

Patients can connect with each other as relatives (bidirectional relationship). Relatives receive delegated permissions to help manage access when the patient is incapacitated.

flowchart LR
    subgraph UserA["Patient A (Owner)"]
        A1["Owns Timeline A"]
        A2["Can create links"]
    end
    subgraph UserB["Patient B (Relative)"]
        B1["Owns Timeline B"]
        B2["Can view Timeline A"]
        B3["Can create links for A"]
    end
    UserA <-- "Relative Connection" --> UserB
Loading

Relative Permissions:

Permission Description
View Timeline Read access to the patient's medical timeline
Create Shareable Links Can generate access links on behalf of the patient
Cannot Revoke Links Only the timeline owner can revoke access

3. Data Models

3.1 Entity Relationship Diagram

erDiagram
    User ||--o{ RelativeConnection : "has"
    User ||--o{ AccessLink : "creates"
    User ||--o{ RefreshToken : "has"
    User ||--o{ AuditLog : "generates"
    User ||--o{ OTPVerification : "receives"

    User {
        int id PK
        string email UK
        string password_hash
        string full_name
        boolean is_verified
        boolean is_active
        boolean mfa_enabled
        string mfa_secret
        string oauth_provider
        string oauth_id
        datetime created_at
        datetime updated_at
        datetime last_login_at
    }

    RelativeConnection {
        int id PK
        int user_id FK "Timeline owner"
        int relative_id FK "Connected relative"
        string relationship_type
        string status "pending/accepted/rejected"
        boolean can_create_links "Delegated permission"
        datetime created_at
    }

    AccessLink {
        int id PK
        int owner_id FK "Timeline owner"
        int created_by_id FK "Creator - owner or relative"
        string token UK
        string access_type "authenticated/one_time_public"
        int max_uses "1 for one-time or null"
        int use_count
        datetime expires_at
        boolean is_revoked
        string label
        datetime created_at
        datetime last_accessed_at
    }

    RefreshToken {
        int id PK
        int user_id FK
        string token UK
        datetime expires_at
        boolean is_revoked
        string device_info
        datetime created_at
    }

    AuditLog {
        int id PK
        int user_id FK
        string action
        string resource_type
        int resource_id
        string ip_address
        string user_agent
        json metadata
        datetime created_at
    }

    OTPVerification {
        int id PK
        int user_id FK
        string otp_code
        string purpose
        datetime expires_at
        boolean is_used
        datetime created_at
    }
Loading

3.2 Model Definitions

User Model

class User(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    email: str = Field(unique=True, index=True, max_length=255)
    password_hash: Optional[str] = None  # Nullable for OAuth users
    full_name: str = Field(max_length=100)
    
    # Verification & Status
    is_verified: bool = Field(default=False)
    is_active: bool = Field(default=True)
    
    # MFA
    mfa_enabled: bool = Field(default=False)
    mfa_secret: Optional[str] = None
    
    # OAuth
    oauth_provider: Optional[str] = None  # 'google'
    oauth_id: Optional[str] = None
    
    # Timestamps
    created_at: datetime
    updated_at: datetime
    last_login_at: Optional[datetime] = None

AccessLink Model (for sharing timeline)

class AccessType(str, Enum):
    AUTHENTICATED = "authenticated"      # Recipient must register/login
    ONE_TIME_PUBLIC = "one_time_public"  # Single-use, no account needed

class AccessLink(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    owner_id: int = Field(foreign_key="user.id", index=True)  # Timeline owner
    created_by_id: int = Field(foreign_key="user.id")  # Creator (owner or relative)
    token: str = Field(unique=True, index=True)  # UUID or secure random
    
    access_type: AccessType
    max_uses: Optional[int] = None  # 1 for one-time, None for unlimited
    use_count: int = Field(default=0)
    expires_at: Optional[datetime] = None  # None = permanent
    is_revoked: bool = Field(default=False)
    
    # Metadata
    label: Optional[str] = None  # "Dr. Smith's link", "Family access"
    created_at: datetime
    last_accessed_at: Optional[datetime] = None

4. Authentication Flow

4.1 Registration Flow

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant Email

    User->>Frontend: Fill registration form
    Frontend->>Backend: POST /register
    
    Note over Backend: Validate password complexity
    Note over Backend: Create user (unverified)
    Note over Backend: Generate OTP
    
    Backend->>Email: Send verification email
    Backend-->>Frontend: 201 Created
    Frontend-->>User: Show OTP input
    
    User->>Frontend: Enter OTP
    Frontend->>Backend: POST /verify-email
    
    Note over Backend: Verify OTP
    Note over Backend: Mark user verified
    
    Backend-->>Frontend: JWT Tokens
    Frontend-->>User: Logged In! Redirect to Dashboard
Loading

4.2 Login Flow (with 2FA)

sequenceDiagram
    participant User
    participant Frontend
    participant Backend

    User->>Frontend: Enter Email + Password
    Frontend->>Backend: POST /login
    
    Note over Backend: Verify credentials
    Note over Backend: Check if MFA enabled
    
    Backend-->>Frontend: {mfa_required: true}
    Frontend-->>User: Show TOTP input
    
    User->>Frontend: Enter TOTP code
    Frontend->>Backend: POST /login/mfa
    
    Note over Backend: Verify TOTP
    Note over Backend: Create session
    Note over Backend: Log audit event
    
    Backend-->>Frontend: JWT Tokens
    Frontend-->>User: Redirect to Dashboard
Loading

4.3 Token Strategy

flowchart TB
    subgraph JWT["JWT Token Structure"]
        subgraph Access["Access Token (Short-lived: 15 minutes)"]
            A1["Header: { alg: HS256, typ: JWT }"]
            A2["Payload: { sub, email, type: access, exp, iat }"]
        end
        subgraph Refresh["Refresh Token (Long-lived: 7 days)"]
            R1["• Stored in HttpOnly cookie"]
            R2["• Hashed in database"]
            R3["• Can be revoked individually"]
            R4["• Tracks device/session info"]
        end
    end
Loading

5. Access Link Sharing Flow

5.1 Access Link Types

Type Description Use Case
Authenticated Recipient must register/login to view Long-term access for relatives, new doctors
One-Time Public Single-use, no account needed Quick share with doctor who won't create account

5.2 Creating a Shareable Link

Who can create links:

  • ✅ Timeline owner (patient)
  • ✅ Connected relatives (with can_create_links permission)
flowchart TD
    subgraph Form["Create Access Link Form"]
        L["Label: Dr. Smith's Access Link"]
        T["Link Type:"]
        T1["○ Authenticated (requires login)"]
        T2["● One-Time Public (single use)"]
        E["Expires: 2025-01-23 14:00 (optional)"]
        B["[Create Link]"]
    end
    
    Form --> Generated["Generated URL: https://medstory.app/share/abc123xyz..."]
Loading

5.3 Authenticated Link Flow (Invitation-Style)

When a user clicks an authenticated link without being logged in, they must register first.

sequenceDiagram
    participant Recipient
    participant Frontend
    participant Backend
    participant Email

    Recipient->>Frontend: Click shared link
    Frontend->>Backend: GET /api/share/:token
    
    Note over Backend: Validate token & check expiry
    
    alt Recipient is logged in
        Backend-->>Frontend: Return timeline data
        Frontend-->>Recipient: Display timeline
    else Recipient not logged in
        Backend-->>Frontend: {requires_auth: true, invitation: true}
        Frontend-->>Recipient: Show Register/Login page
        
        Recipient->>Frontend: Register with email
        Frontend->>Backend: POST /api/auth/register
        Backend->>Email: Send verification OTP
        
        Recipient->>Frontend: Verify OTP
        Frontend->>Backend: POST /api/auth/verify-email
        Backend-->>Frontend: JWT Tokens + Redirect to shared timeline
        
        Frontend-->>Recipient: Display timeline
    end
    
    Note over Backend: Log audit event
Loading

5.4 One-Time Public Link Flow

For doctors who don't want to create an account. Link becomes invalid after first use.

sequenceDiagram
    participant Doctor
    participant Frontend
    participant Backend

    Doctor->>Frontend: Click one-time link
    Frontend->>Backend: GET /api/share/:token
    
    Note over Backend: Validate token
    Note over Backend: Check use_count < max_uses
    Note over Backend: Check if not expired/revoked
    
    alt Link is valid (not used)
        Backend-->>Frontend: Timeline data
        Note over Backend: Increment use_count to 1
        Note over Backend: Log audit event
        Frontend-->>Doctor: Display timeline (read-only)
    else Link already used
        Backend-->>Frontend: {error: "Link has expired"}
        Frontend-->>Doctor: Show "Link no longer valid" message
    end
Loading

5.5 Link Access Summary

flowchart TB
    subgraph Creation["Link Creation"]
        Owner["Patient (Owner)"]
        Relative["Relative (Delegated)"]
    end
    
    subgraph Types["Link Types"]
        Auth["Authenticated Link"]
        OneTime["One-Time Public Link"]
    end
    
    subgraph Access["Access Flow"]
        AuthFlow["Register/Login Required"]
        PublicFlow["Immediate Access (once)"]
    end
    
    Owner --> Auth
    Owner --> OneTime
    Relative --> Auth
    Relative --> OneTime
    
    Auth --> AuthFlow
    OneTime --> PublicFlow
Loading

6. API Endpoints Design

6.1 Authentication Endpoints

Method Endpoint Description
POST /api/auth/register Register new user
POST /api/auth/verify-email Verify email with OTP
POST /api/auth/resend-otp Resend verification OTP
POST /api/auth/login Login with email/password
POST /api/auth/login/mfa Complete MFA verification
POST /api/auth/refresh Refresh access token
POST /api/auth/logout Logout (revoke refresh token)
POST /api/auth/forgot-password Request password reset
POST /api/auth/reset-password Reset password with token
GET /api/auth/oauth/google Initiate Google OAuth
GET /api/auth/oauth/google/callback Google OAuth callback

6.2 User Management Endpoints

Method Endpoint Description
GET /api/users/me Get current user profile
PATCH /api/users/me Update profile
POST /api/users/me/change-password Change password
POST /api/users/me/enable-mfa Enable 2FA
POST /api/users/me/disable-mfa Disable 2FA
GET /api/users/me/sessions List active sessions
DELETE /api/users/me/sessions/:id Revoke a session

6.3 Access & Sharing Endpoints

Method Endpoint Description
POST /api/access-links Create access link (owner or relative)
GET /api/access-links List access links for my timeline
GET /api/access-links/created-by-me List links I created (including for relatives)
DELETE /api/access-links/:id Revoke access link (owner only)
GET /api/share/:token Access shared timeline via link
GET /api/share/:token/info Get link metadata (without accessing)

6.4 Relative Connections Endpoints

Method Endpoint Description
POST /api/relatives/invite Invite user as relative
GET /api/relatives List my relatives
GET /api/relatives/requests Pending connection requests
POST /api/relatives/accept/:id Accept connection
DELETE /api/relatives/:id Remove relative connection

7. Security Measures

7.1 Password Requirements

flowchart TB
    subgraph Rules["Password Complexity Rules"]
        direction TB
        R1["✓ Minimum 8 characters"]
        R2["✓ At least 1 uppercase letter (A-Z)"]
        R3["✓ At least 1 lowercase letter (a-z)"]
        R4["✓ At least 1 digit (0-9)"]
        R5["✓ At least 1 special character (!@#$%^&*...)"]
        R6["✗ Cannot contain email or name"]
        R7["✗ Cannot be a common password"]
    end
Loading

7.2 Session Management

Setting Value Notes
Access Token TTL 15 minutes Short-lived for security
Refresh Token TTL 7 days Configurable via env
Idle Timeout 30 minutes Configurable via env
Max Active Sessions 5 Per user
Session Storage HttpOnly Cookie Refresh token

7.3 Rate Limiting

Endpoint Limit Window
/api/auth/login 5 attempts 15 minutes
/api/auth/register 3 attempts 1 hour
/api/auth/forgot-password 3 attempts 1 hour
/api/auth/verify-email 5 attempts 15 minutes
General API 100 requests 1 minute

7.4 Audit Logging

All security-relevant events are logged:

class AuditAction(str, Enum):
    LOGIN_SUCCESS = "login_success"
    LOGIN_FAILED = "login_failed"
    LOGOUT = "logout"
    PASSWORD_CHANGED = "password_changed"
    PASSWORD_RESET = "password_reset"
    MFA_ENABLED = "mfa_enabled"
    MFA_DISABLED = "mfa_disabled"
    ACCESS_LINK_CREATED = "access_link_created"
    ACCESS_LINK_REVOKED = "access_link_revoked"
    TIMELINE_ACCESSED = "timeline_accessed"
    RELATIVE_CONNECTED = "relative_connected"
    RELATIVE_REMOVED = "relative_removed"

8. Implementation Phases

Timeline Overview

gantt
    title Authorization & Security Implementation
    dateFormat  YYYY-MM-DD
    
    section Phase 1
    User model & migrations       :p1a, 2025-01-06, 3d
    Password hashing             :p1b, after p1a, 2d
    Registration endpoint        :p1c, after p1b, 2d
    Email verification (OTP)     :p1d, after p1c, 2d
    Login with JWT               :p1e, after p1d, 2d
    Refresh token mechanism      :p1f, after p1e, 2d
    Logout & password reset      :p1g, after p1f, 3d
    
    section Phase 2
    Two-Factor Auth (TOTP)       :p2a, after p1g, 3d
    Rate limiting                :p2b, after p2a, 2d
    Session management           :p2c, after p2b, 2d
    Audit logging                :p2d, after p2c, 2d
    
    section Phase 3
    Google OAuth                 :p3a, after p2d, 3d
    Account linking              :p3b, after p3a, 2d
    
    section Phase 4
    Access link generation       :p4a, after p3b, 2d
    Authenticated link flow      :p4b, after p4a, 2d
    One-time public link         :p4c, after p4b, 2d
    Relative delegation          :p4d, after p4c, 2d
    
    section Phase 5
    Invite system                :p5a, after p4d, 2d
    Connection requests          :p5b, after p5a, 2d
    Relative timeline access     :p5c, after p5b, 2d
    Delegated link creation      :p5d, after p5c, 2d
    
    section Phase 6
    Login/Register screens       :p6a, after p5d, 3d
    Token storage & refresh      :p6b, after p6a, 2d
    OAuth flow integration       :p6c, after p6b, 3d
    MFA & Access link UI         :p6d, after p6c, 3d
Loading

Phase 1: Core Authentication (Week 1-2)

  • User model & Alembic database migrations
  • Password hashing (bcrypt/argon2)
  • Registration endpoint with validation
  • Email verification with OTP
  • Login endpoint with JWT generation
  • Refresh token mechanism
  • Logout & session invalidation
  • Password reset flow

Phase 2: Enhanced Security (Week 3)

  • Two-Factor Authentication (TOTP)
  • Rate limiting middleware
  • Session management (list/revoke)
  • Audit logging system
  • Password complexity validation

Phase 3: OAuth Integration (Week 4)

  • Google OAuth implementation
  • Account linking (OAuth + password)

Phase 4: Access Sharing (Week 5)

  • Access link model & Alembic migrations
  • Authenticated link flow (invitation-style)
  • One-time public link flow
  • Link expiry & revocation
  • Use count tracking

Phase 5: Relative Connections (Week 6)

  • Relative connection model & migrations
  • Invite system with email
  • Connection request handling
  • Relative timeline access (view)
  • Delegated link creation permission

Phase 6: Frontend Integration (Week 7-8)

  • Login/Register screens (Flutter)
  • Token storage & refresh logic
  • OAuth flow integration
  • MFA setup screens
  • Access link management UI
  • Relative connection UI

9. Alembic Database Migrations

This project uses Alembic for database schema migrations. All schema changes must be managed through Alembic migrations.

9.1 Migration Workflow

flowchart LR
    A["Modify models.py"] --> B["Generate migration"]
    B --> C["Review migration file"]
    C --> D["Apply migration"]
    D --> E["Commit changes"]
Loading

9.2 Common Commands

# Navigate to backend directory
cd backend

# Generate a new migration after modifying models
alembic revision --autogenerate -m "Add user and auth models"

# Apply all pending migrations
alembic upgrade head

# Rollback last migration
alembic downgrade -1

# View current migration status
alembic current

# View migration history
alembic history --verbose

9.3 Migration Files Structure

backend/
├── alembic/
│   ├── versions/
│   │   ├── 001_initial_schema.py
│   │   ├── 002_add_user_model.py
│   │   ├── 003_add_access_link_model.py
│   │   ├── 004_add_relative_connection.py
│   │   └── ...
│   ├── env.py
│   └── script.py.mako
├── alembic.ini
└── app/
    └── models.py

9.4 Migration Best Practices

Practice Description
Descriptive names Use clear names like add_user_mfa_fields not update_user
Review before apply Always review generated migrations for correctness
Atomic changes One logical change per migration
Backward compatible Consider rollback scenarios
Test migrations Test on a copy of production data before deploying

9.5 Planned Migrations

Migration Description Phase
add_user_model User table with auth fields Phase 1
add_otp_verification OTP verification table Phase 1
add_refresh_token Refresh token storage Phase 1
add_audit_log Audit logging table Phase 2
add_access_link Access link with types (authenticated/one-time) Phase 4
add_relative_connection Relative connections with permissions Phase 5

10. Dependencies to Add

Backend (requirements.txt)

python-jose[cryptography]  # JWT handling
passlib[bcrypt]            # Password hashing
pyotp                      # TOTP for 2FA
httpx                      # Async HTTP for OAuth
slowapi                    # Rate limiting
aiosmtplib                 # Async email sending

Frontend (pubspec.yaml)

dependencies:
  flutter_secure_storage: ^9.0.0   # Secure token storage
  google_sign_in: ^6.1.0           # Google OAuth
  local_auth: ^2.1.0               # Biometric auth (future)

11. Environment Variables

# JWT Configuration
JWT_SECRET_KEY=<32+ character random string>
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=7

# Session Configuration
SESSION_IDLE_TIMEOUT_MINUTES=30
MAX_SESSIONS_PER_USER=5

# Email Configuration
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@medstory.app
SMTP_PASSWORD=<email password>
EMAIL_FROM=MedStory <noreply@medstory.app>

# OAuth Configuration (Google only)
GOOGLE_CLIENT_ID=<google client id>
GOOGLE_CLIENT_SECRET=<google client secret>

# Security
RATE_LIMIT_ENABLED=true
OTP_EXPIRE_MINUTES=10
PASSWORD_RESET_EXPIRE_HOURS=24

# Access Links
ONE_TIME_LINK_EXPIRY_HOURS=24  # Default expiry for one-time public links

12. Open Questions / Future Considerations

  1. Email Service: Which email provider to use? (SendGrid, AWS SES, Mailgun)
  2. Database: Stay with SQLite for MVP or migrate to PostgreSQL?
  3. Deployment: Session storage strategy for multiple instances?
  4. Mobile: Will there be native mobile apps needing different OAuth flows?
  5. HIPAA: Full compliance audit needed before production?

13. Approval & Next Steps

Please review this plan and confirm:

  • Data models look correct
  • Authentication flows are acceptable
  • API endpoint design is approved
  • Implementation phases are prioritized correctly
  • Security measures are sufficient for MVP

Once approved, I will proceed with Phase 1: Core Authentication implementation.


Document maintained by: AI Assistant
Last updated: 2025-12-23

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment