Skip to content

Rizu0007/microsoft-365-oauth-manager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

M365 Email Forwarder

What This Application Does

This application is a Node.js backend service that enables users to connect and manage multiple Microsoft 365 email accounts through a centralized OAuth2 authentication system. When a user wants to add their Microsoft account, the application initiates a secure authentication flow with Microsoft Azure AD, redirecting them to Microsoft's login page. After successful authentication and permission grants, Microsoft returns an authorization code which the application exchanges for access and refresh tokens. These tokens are then encrypted using AES encryption and stored in both a SQLite database and individual INI files for each account, providing redundancy and portability. The application continuously monitors token expiration times through a background cron service that runs every 30 minutes, automatically refreshing tokens that are about to expire to maintain uninterrupted access to Microsoft Graph APIs.

Features

  • Multi-Account OAuth2 Authentication: Seamlessly connect multiple Microsoft 365 accounts from different organizations using the standard OAuth2 authorization code flow with PKCE support.

  • Automatic Token Refresh Service: Background cron job runs every 30 minutes to check token expiration times and automatically refreshes tokens that expire within 5 minutes, ensuring continuous API access.

  • Dual Storage System: Tokens are stored in both SQLite database for structured queries and INI files for easy backup and portability, with both storage methods using encrypted tokens.

  • Microsoft Graph API Integration: Full delegated permissions for Mail.Read, Mail.ReadWrite, Mail.Send, User.Read, and People.Read, allowing comprehensive email and user data management.

  • Multi-Tenant Support: Handles accounts from different Microsoft 365 organizations simultaneously, capturing and managing tenant IDs for proper authentication context.

  • Comprehensive Error Handling: Tracks error counts for each account, logs detailed error information, and can automatically disable accounts after repeated token refresh failures.

  • Production-Ready Logging: Winston-based logging system with separate error and combined log files, configurable log levels, and JSON-formatted logs for easy parsing.

  • RESTful API Design: Clean API endpoints with proper status codes, error messages, and JSON responses for easy integration with frontend applications.

  • Graceful Shutdown: Handles SIGTERM and SIGINT signals properly, allowing the application to shut down cleanly without losing data or connections.

  • Security Headers: Implements Helmet middleware for setting secure HTTP headers and CORS configuration for controlled cross-origin access.

Prerequisites

Before running this application, ensure you have the following installed and configured:

  • Node.js (version 14 or higher)
  • npm (comes with Node.js)
  • SQLite3 (usually comes pre-installed on most systems)
  • Microsoft Azure AD App Registration (see setup instructions below)

Installation

Clone the repository and install dependencies:

git clone https://github.com/yourusername/m365-email-forwarder.git
cd m365-email-forwarder
npm install

Azure AD App Registration Setup

You need to create an app registration in Azure AD to enable OAuth2 authentication:

  1. Navigate to the Azure Portal
  2. Go to Azure Active DirectoryApp registrationsNew registration
  3. Configure your app:
    • Name: M365 Email Forwarder (or your preferred name)
    • Supported account types: Select "Accounts in any organizational directory (Any Azure AD directory - Multitenant)"
    • Redirect URI: Select "Web" and enter http://localhost:3001/api/auth/callback (or your production callback URL)
  4. After creation, go to Certificates & secrets and create a new client secret. Copy this value immediately as it won't be shown again.
  5. Go to API permissions and add the following Delegated permissions for Microsoft Graph:
    • Mail.Read
    • Mail.ReadWrite
    • Mail.Send
    • User.Read
    • People.Read
  6. Click Grant admin consent if you have admin privileges (optional but recommended)
  7. Copy the Application (client) ID from the Overview page

Environment Variables

Create a .env file in the root directory with the following configuration:

# Server Configuration
PORT=3001
NODE_ENV=development

# Frontend URL for OAuth redirects
FRONTEND_URL=http://localhost:3000

# Microsoft Azure AD Configuration
MICROSOFT_CLIENT_ID=your_application_client_id_here
MICROSOFT_CLIENT_SECRET=your_client_secret_here
MICROSOFT_REDIRECT_URI=http://localhost:3001/api/auth/callback

# Security - Change this to a strong random string in production
ENCRYPTION_KEY=your_secure_encryption_key_change_in_production

# Database Configuration
DB_PATH=./storage/database.sqlite

# Logging Configuration
LOG_LEVEL=info

Important Notes:

  • Replace your_application_client_id_here with the Application (client) ID from Azure
  • Replace your_client_secret_here with the client secret you generated
  • Generate a strong random string for ENCRYPTION_KEY in production (at least 32 characters)
  • Update MICROSOFT_REDIRECT_URI to match your production URL when deploying
  • Never commit the .env file to version control

Running the Application

Development Mode (with auto-restart on file changes):

npm run dev

Production Mode:

npm start

The server will start on http://localhost:3001 (or the PORT specified in your .env file)

API Endpoints

Authentication Endpoints

GET /api/auth/login

  • Initiates the OAuth2 login flow
  • Returns the Microsoft authorization URL and a state token for CSRF protection
  • Frontend should redirect users to the returned authUrl

GET /api/auth/callback

  • Handles the OAuth2 callback from Microsoft
  • Exchanges authorization code for access and refresh tokens
  • Stores encrypted tokens in database and INI files
  • Redirects to frontend with success or error parameters

Account Management Endpoints

GET /api/accounts

  • Lists all connected Microsoft 365 accounts
  • Returns account information without exposing sensitive tokens
  • Shows account status, creation date, and display names

Health Check

GET /api/health

  • Returns server health status, timestamp, version, and environment
  • Useful for monitoring and load balancer health checks

Project Structure

m365-email-forwarder/
├── config/
│   ├── database.js          # SQLite database initialization and schema
│   └── microsoft.js         # MSAL configuration and Graph client factory
├── controllers/
│   ├── accountController.js # Account management logic
│   └── authController.js    # OAuth flow handlers
├── middleware/
│   └── auth.js              # Authentication middleware
├── routes/
│   ├── accounts.js          # Account management routes
│   └── auth.js              # Authentication routes
├── services/
│   ├── microsoftGraphService.js  # Microsoft Graph API interactions
│   ├── tokenRefreshService.js    # Background token refresh cron job
│   └── tokenService.js           # Token CRUD operations and encryption
├── storage/
│   ├── database.sqlite      # SQLite database (auto-created)
│   ├── tokens/              # INI backup files (auto-created)
│   ├── error.log            # Error logs
│   └── combined.log         # Combined logs
├── utils/
│   ├── encryption.js        # AES encryption/decryption utilities
│   └── logger.js            # Winston logger configuration
├── .env                     # Environment variables (not in git)
├── .gitignore
├── package.json
└── server.js                # Main application entry point

How It Works

The application follows a standard OAuth2 authorization code flow. When a user clicks "Connect Microsoft Account" in your frontend, you make a request to /api/auth/login which returns a Microsoft authorization URL. The user is redirected to this URL where they log in with their Microsoft credentials and grant the requested permissions. Microsoft then redirects back to your callback URL (/api/auth/callback) with an authorization code. The application exchanges this code for access and refresh tokens using MSAL, retrieves the user's profile information from Microsoft Graph to verify access, encrypts both tokens using AES-256, and stores them in the SQLite database along with metadata like email, tenant ID, display name, and expiration time. A duplicate copy is also saved as an INI file for backup purposes.

Once tokens are stored, the background refresh service monitors their expiration. Every 30 minutes, it queries all active accounts and checks if any tokens will expire within the next 5 minutes. For expiring tokens, it uses MSAL's silent token acquisition with the refresh token to get new access tokens without user interaction. The new tokens are encrypted and updated in both storage locations. If token refresh fails three times consecutively, the account can be automatically disabled to prevent repeated API calls.

Security Features

Token Encryption: All access and refresh tokens are encrypted using AES-256 encryption before being stored in the database or INI files. The encryption key is stored in environment variables and should be a strong random string in production. This ensures that even if someone gains access to the database or file system, they cannot use the tokens without the encryption key.

Environment-Based Secrets: Sensitive configuration like client secrets, encryption keys, and database paths are stored in environment variables rather than hardcoded in the application. This follows the twelve-factor app methodology and prevents accidental exposure of credentials in version control.

HTTPS Redirect URIs: In production, all OAuth redirect URIs should use HTTPS to prevent man-in-the-middle attacks during the authorization code exchange. The application supports configurable redirect URIs through environment variables.

Helmet Security Headers: The Express application uses Helmet middleware which sets various HTTP headers to protect against common web vulnerabilities like XSS, clickjacking, and MIME type sniffing. This includes headers like X-Frame-Options, X-Content-Type-Options, and Content-Security-Policy.

CORS Configuration: Cross-Origin Resource Sharing (CORS) is configured to only allow requests from the specified frontend URL, preventing unauthorized domains from accessing the API. This is controlled through the FRONTEND_URL environment variable.

State Token CSRF Protection: The OAuth flow generates a unique state token for each authentication request using UUID v4. This token should be validated on callback to prevent Cross-Site Request Forgery attacks (though this validation is not fully implemented in the current codebase).

SQL Injection Prevention: All database queries use parameterized statements rather than string concatenation, preventing SQL injection attacks. The sqlite3 library automatically escapes values when using the ? placeholder syntax.

Error Message Sanitization: In production mode, detailed error messages are suppressed from API responses, only returning generic error messages to clients. Full error details are logged to files but not exposed to potential attackers.

Account Error Tracking: The system tracks failed token refresh attempts and can automatically disable accounts after repeated failures. This prevents potential abuse and alerts administrators to accounts that may have had their refresh tokens revoked.

Graceful Shutdown: The application properly handles shutdown signals (SIGTERM, SIGINT) to ensure in-flight requests complete and database connections close properly, preventing data corruption or token loss during deployment or restart scenarios.

About

Node.js backend service for managing multiple Microsoft 365 email accounts with OAuth2 authentication, automatic token refresh, and encrypted credential storage using Microsoft Graph API

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors