OpenWork MCP OAuth Security Considerations: Enterprise-Grade Protection in a Mock Server

OpenWork's MCP OAuth implementation mitigates common attack vectors through strict redirect-URI validation, PKCE enforcement, dynamic client registration, and comprehensive token lifecycle management.

The different-ai/openwork repository provides a Model-Context-Protocol (MCP) mock server that implements a synthetic OAuth 2.0 provider for deterministic testing. Understanding the OpenWork MCP OAuth security considerations is essential for developers integrating enterprise connectors, as the implementation balances realistic flow simulation with defensive checks against open redirects, credential leakage, and token replay attacks.

Redirect-URI Validation and Open Redirect Prevention

The implementation strictly validates redirect URIs to prevent open-redirect attacks. In packages/enterprise-mcp-mock-server/src/contracts/oauth.ts, the isSafeOAuthRedirectUri utility enforces that URIs contain no user-info, no fragment, and use HTTPS unless the host is localhost (localhost, 127.0.0.1, or [::1]).

This check ensures that authorization codes cannot be diverted to attacker-controlled endpoints during the flow.

import { isSafeOAuthRedirectUri } from '@modelcontextprotocol/sdk/shared/auth.js';

if (!isSafeOAuthRedirectUri(redirectUri)) {
  throw new Error('Unsafe redirect URI');
}

Dynamic Client Registration Requirements

The handler enforces dynamic client registration (DCR) when scenarios require it. Located in packages/enterprise-mcp-mock-server/src/protocol/oauth-handler.ts (lines 151-161), the code rejects manual OAuth authorization requests when the dcr-required fault is active.

This ensures clients are properly registered and validated before any authorization request proceeds, preventing unauthorized client impersonation.

PKCE Enforcement Against Code Interception

To mitigate authorization code interception attacks, the implementation enforces PKCE (Proof Key for Code Exchange) with S256 method validation. The handler validates code_challenge against pkceS256ChallengePattern and later verifies the verifier using pkceVerifierPattern with a timing-safe equality check (lines 120-127 in oauth-handler.ts).

const verifier = form.get('code_verifier')!;
if (!pkceVerifierPattern.test(verifier) ||
    !safeEqual(storedCodeChallenge, pkceChallenge(verifier))) {
  sendOAuthError(res, 400, 'invalid_grant', 'PKCE verification failed');
}

Client Secret Verification and Credential Protection

The sendInvalidClient function (lines 69-82 in oauth-handler.ts) handles client authentication failures with provider-specific error formatting for Microsoft and ServiceNow. The system maintains strict secret length requirements enforced by the in-memory state store in src/runtime/instance-state.ts, protecting against credential leakage through brute-force or guessing attacks.

Scope Validation and Privilege Limitation

Scope validation prevents over-privilege by rejecting requests where the scope parameter is empty or includes any scope not listed in scenario.oauth.authorizationScopes (lines 172-179). This ensures tokens are issued only with explicitly defined permissions, adhering to the principle of least privilege.

Token Lifecycle Management and Revocation

Token issuance follows strict lifetime policies: access tokens expire after 1 hour and refresh tokens expire after 30 days. The issueTokenResponse function (lines 389-418) creates opaque tokens and records expiration metadata.

For security events, revokeTokenFamily (lines 430-438) performs cascade deletion of all access and refresh tokens sharing the same familyId, preventing token reuse after compromise.

function revokeTokenFamily(state, familyId) {
  for (const [token, rec] of state.tokens) {
    if (rec.familyId === familyId) state.tokens.delete(token);
  }
  for (const [token, rec] of state.refreshTokens) {
    if (rec.familyId === familyId) state.refreshTokens.delete(token);
  }
}

Fault Injection for Controlled Testing

The implementation includes faultApplies and emitFault hooks (lines 38-46) that enable controlled fault simulation without disabling underlying validation logic. This allows developers to test error scenarios—such as invalid grants or server errors—while maintaining the integrity of security boundaries.

Summary

  • Redirect-URI validation in oauth.ts blocks open-redirect attacks by enforcing HTTPS and localhost safety checks.
  • Dynamic client registration requirements prevent unauthorized clients from initiating flows in oauth-handler.ts.
  • PKCE enforcement using pkceS256ChallengePattern and timing-safe comparison mitigates code interception.
  • Client secret verification includes provider-specific error handling and minimum length requirements.
  • Scope validation ensures tokens are issued only with explicitly permitted scopes defined in the active scenario.
  • Token lifecycle management provides 1-hour access token and 30-day refresh token expiration with family-based revocation.
  • Fault injection hooks allow realistic error testing while preserving security control flow.

Frequently Asked Questions

How does OpenWork prevent open-redirect vulnerabilities in OAuth flows?

OpenWork prevents open-redirect attacks through the isSafeOAuthRedirectUri utility in src/contracts/oauth.ts, which validates that redirect URIs contain no user-info, no fragment, and use HTTPS unless pointing to localhost (localhost, 127.0.0.1, or [::1]). This ensures authorization codes cannot be diverted to malicious endpoints during the authentication flow.

What PKCE validation does the OpenWork MCP server enforce?

The server enforces PKCE S256 method validation using regex patterns pkceS256ChallengePattern and pkceVerifierPattern in src/protocol/oauth-handler.ts. During token exchange, it performs a timing-safe equality check between the stored code challenge and the hash of the provided verifier, preventing authorization code interception attacks.

How are refresh tokens revoked in case of compromise?

The revokeTokenFamily function in src/protocol/oauth-handler.ts (lines 430-438) implements cascade revocation by iterating through token maps and deleting all access and refresh tokens sharing the same familyId. This ensures that compromising one token invalidates the entire token family, preventing replay attacks.

Does the mock server support dynamic client registration?

Yes, the implementation supports dynamic client registration (DCR) through endpoints defined in src/protocol/oauth-handler.ts. When scenarios require DCR (via the dcr-required fault), the server rejects manual authorization attempts and requires clients to register via the /oauth/registration endpoint, issuing opaque client IDs and secrets through state.issueOpaque().

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 →