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_configstable stores provider metadata:authorize_url,token_url,scope,client_id, andclient_secretintegration_connectionstable links users and workspaces to providers, trackingauth_mode,granted_scopes, and asecret_refpointer 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:
- Detection:
runtime/harnesses/src/mcp.tsintercepts 401/403 responses and setsauthRequiredflag - State marking: Connection status changes to
needs_reauthinintegration_connections - UI triggering: Next tool invocation automatically renders the authorization prompt
- 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →