How holaOS Handles User Authentication and Authorization: OAuth 2.0 Architecture Explained

holaOS implements a centralized OAuth 2.0-based authentication model with three-layer architecture: provider configuration storage, authorization flow management, and runtime token enforcement that automatically prompts users for re-authorization when tokens expire.

The open-source holaOS project (holaboss-ai/holaOS) provides a secure, extensible framework for managing third-party service access. Its authentication and authorization系统设计 prioritizes user control, token isolation, and seamless UI integration—ensuring every request to integrated services carries a fresh, user-approved credential.


Three-Layer Authentication Architecture

holaOS structures its authentication and authorization system into distinct layers that operate from configuration through runtime enforcement.

1. OAuth Configuration Storage Layer

All third-party authentication providers are defined in runtime/state-store/src/store.ts. The schema separates provider definitions from user-specific connections:

  • oauth_app_configs table stores provider metadata: authorize_url, token_url, scope, client_id, and client_secret
  • integration_connections table links users and workspaces to providers, tracking auth_mode, granted_scopes, and a secret_ref pointer to the actual token

This design enables provider-agnostic OAuth definition—adding a new service requires only inserting a configuration row without code changes.

2. Authorization Flow Layer (OAuth 2.0)

The flow implementation in runtime/api-server/src/oauth-service.ts handles the complete handshake:

  • startFlow(providerId, ownerUserId): Constructs the authorization URL with PKCE parameters and returns it to the frontend
  • Callback endpoint (/api/v1/integrations/oauth/callback): Exchanges the authorization code for tokens and persists the connection record
// Starting an OAuth flow from the client
const resp = await fetch('/api/v1/integrations/oauth/authorize', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ providerId: 'google', ownerUserId: user.id })
});
const { authorize_url } = await resp.json();
window.open(authorize_url, '_blank');

Source: runtime/api-server/src/app.ts — POST handler delegates to OAuthService.startFlow at line 5618

3. Runtime Enforcement Layer

Three mechanisms ensure tokens remain valid and requests are properly authorized:

MCP Server Authorization

runtime/harness-host/src/mcp-authorize.ts executes the authorize-mcp sub-command, storing tokens in a per-workspace secure cache (mcp-oauth/ directory) rather than the main database. This isolates secrets and enables workspace-scoped token rotation.

API Gatekeeper Middleware

runtime/api-server/src/app.ts contains middleware that validates inbound requests:

function requireAuth(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers['authorization'];
  if (!authHeader) return sendError(res, 401, 'unauthorized');
  const token = tokenCache.get(authHeader.split(' ')[1]);
  if (!token) return sendError(res, 401, 'unauthorized');
  next();
}

Missing or invalid tokens trigger 401 Unauthorized responses. Connections in needs_reauth state receive the same treatment, forcing re-authentication.

Automatic Re-Authorization

When tools detect expired credentials, runtime/harnesses/src/runtime-agent-tools.ts exposes the mcp_reauthorize tool:

{
  id: 'mcp_reauthorize',
  description: 'Re-run the OAuth sign-in for an already-connected remote MCP server.',
  args: [{ name: 'server', type: 'string' }],
  handler: async ({ server }) => {
    // Returns UI card with re-authorize button triggering authorizeMcpServer(server, { reauthorize: true })
  }
}

This surfaces an inline Re-authorize button that launches a fresh OAuth flow without creating duplicate integration records.


Token Storage Security Model

holaOS employs a reference-based token architecture that keeps sensitive credentials out of the database:

Component Location Purpose
Token metadata integration_connections table Links user/workspace to provider, tracks status
Actual tokens On-disk cache (mcp-oauth/) Cryptographically isolated, workspace-scoped
Reference pointer secret_ref field in record Enables token rotation without DB migration

This separation means a database compromise does not expose live OAuth tokens—a critical defense-in-depth measure for authentication and authorization systems.


Handling Expired Credentials

The runtime gracefully manages token expiration through state transitions:

  1. Detection: runtime/harnesses/src/mcp.ts intercepts 401/403 responses and sets authRequired flag
  2. State marking: Connection status changes to needs_reauth in integration_connections
  3. UI triggering: Next tool invocation automatically renders the authorization prompt
  4. Recovery: User clicks through OAuth flow, new token replaces cached entry via authorize-mcp

This automatic UI prompting eliminates manual token management while maintaining security boundaries.


Key Implementation Files

File Path Responsibility
runtime/state-store/src/store.ts SQLite schema for OAuth configs and user connections
runtime/api-server/src/oauth-service.ts OAuth flow initiation and token exchange
runtime/api-server/src/app.ts Authorization endpoints and 401 enforcement middleware
runtime/harness-host/src/mcp-authorize.ts MCP server token acquisition and cache management
runtime/harnesses/src/runtime-agent-tools.ts mcp_reauthorize tool for credential refresh
runtime/harnesses/src/mcp.ts Authentication failure detection and state management

Summary

  • holaOS authentication and authorization centers on OAuth 2.0 with provider-agnostic configuration storage
  • Three-layer architecture separates concerns: configuration, flow orchestration, and runtime enforcement
  • Token isolation via on-disk cache with database references protects against credential leaks
  • Automatic re-authorization flows keep user experience seamless without sacrificing security
  • MCP-specific tooling enables LLM agents to request credential refreshes through structured UI interactions

Frequently Asked Questions

How does holaOS store OAuth tokens securely?

Tokens are never stored in the main database. Instead, runtime/harness-host/src/mcp-authorize.ts writes them to a per-workspace secure cache on disk, while integration_connections holds only a secret_ref pointer. This design isolates secrets from SQL queries and enables granular token rotation.

What happens when a third-party token expires?

The MCP harness detects 401/403 responses and marks the connection needs_reauth. The next time the tool is invoked, runtime/harnesses/src/runtime-agent-tools.ts surfaces a Re-authorize button that triggers authorizeMcpServer(server, { reauthorize: true })—reusing the existing integration record rather than creating a new one.

Can holaOS support custom OAuth providers?

Yes. Adding a provider requires only inserting a row into oauth_app_configs with authorize_url, token_url, scope, and credentials. The startFlow() method in runtime/api-server/src/oauth-service.ts dynamically constructs URLs from this configuration, requiring no code changes for new providers.

How does the API server reject unauthorized requests?

Middleware in runtime/api-server/src/app.ts validates the Authorization header against the token cache. Missing headers, invalid tokens, or connections in needs_reauth state all return 401 Unauthorized. The same middleware handles the /api/v1/integrations/oauth/authorize endpoint for initiating new flows.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →