Tutorials Logic, IN info@tutorialslogic.com

Authorization: OAuth, Capability Filtering, and Enterprise Access Control

MCP Authorization

Authorization is where MCP stops being a demo and starts behaving like a production interface to real systems. Remote MCP servers should authenticate callers, map them to scopes or entitlements, and enforce those checks per capability.

The current MCP authorization model is transport-level and OAuth-based for HTTP deployments. Capability filtering and per-call authorization still remain server responsibilities.

Authorization Layers

Layer What It Answers
Authentication Who is calling this server?
Capability filtering What should this caller even see in tools/list or resources/list?
Per-call authorization Can this caller perform this exact action on this exact target right now?
Auditing What happened, who did it, and why was it allowed or denied?

Identity and Authority

Authentication establishes identity. Authorization establishes allowed actions. That distinction matters because many MCP servers serve both read-only and write capabilities, and users often need access to some but not all of them.

Do not rely on host names, friendly labels, or client UI identity alone. Remote MCP servers should verify real credentials and tie them to durable access policy.

  • Identity comes first
  • Scope mapping comes second
  • Every sensitive tool or resource should still enforce policy at execution time

OAuth Discovery

Current MCP authorization guidance for HTTP-based transports uses OAuth 2.x patterns. The specification requires clients to discover authorization information through OAuth protected resource metadata instead of guessing or hardcoding token endpoints.

That requirement matters for enterprise consistency. It lets resource servers describe how authorization works in a machine-readable way while keeping the MCP endpoint and auth metadata aligned.

  • Use protected resource metadata discovery for remote MCP servers
  • Keep transport-level auth aligned with standard OAuth practices
  • Design scopes around real capability boundaries rather than generic full-access tokens

Capability Filtering

Authorization should influence discovery as well as execution. If a caller does not have permission to use deployment tools, they generally should not see those tools in normal listings at all.

That reduces accidental misuse and makes host UX cleaner. It also avoids teaching the model about capabilities it should never try to invoke for that user.

  • Filter tools, resources, and prompts to the caller where possible
  • Separate read scopes from write scopes
  • Keep especially destructive tools behind stronger policy and approvals

Per-Call Enforcement

Filtering alone is not enough. Access control must still run during the actual call because permissions can change, dynamic targets can be sensitive, and list views can become stale.

For example, a user may be allowed to read policy documents generally but not read one confidential HR investigation report. That check belongs in the resource read or tool handler, not only at list time.

Simple Scope Gate in a Tool Handler

Simple Scope Gate in a Tool Handler
type SessionUser = {
  id: string;
  scopes: string[];
};

function requireScope(user: SessionUser, scope: string): void {
  if (!user.scopes.includes(scope)) {
    throw new Error(`Missing required scope: ${scope}`);
  }
}

server.registerTool(
  'create_ticket',
  {
    description: 'Create an incident ticket in the approved queue.',
    inputSchema: {
      title: z.string().min(10),
    },
  },
  async ({ title }, extra) => {
    const user = extra.authInfo as SessionUser;
    requireScope(user, 'tickets:write');

    const ticketId = await createTicket(title, user.id);
    return {
      content: [{ type: 'text', text: `Created ticket ${ticketId}` }],
    };
  }
);
  • This demonstrates the shape of per-call enforcement.
  • Real systems usually combine scopes with object-level checks.

Authorization Layers

Authentication answers who is calling. Authorization answers what that caller may do now. In MCP systems, authorization must exist at transport, discovery, invocation, and object levels. A token with a broad read scope may allow connecting to the server, but it should not automatically allow reading every customer, ticket, file, or report.

Discovery filtering is helpful but not sufficient. A host may cache capabilities, a user role may change, or a model may call a capability through a path that was previously visible. The server must repeat authorization at invocation time using the current identity, tenant, scopes, target object, and action. Sensitive tools should also record the reason a request was allowed or denied.

For remote servers, align MCP authorization with the organization existing identity model. Use OAuth metadata discovery where applicable, map scopes to capability families, and keep object-level policy close to the backend source of truth. Avoid inventing a parallel permission model that drifts away from production systems.

  • Authorize discovery and invocation separately.
  • Check tenant and object ownership on every sensitive call.
  • Use narrow scopes that map to capability families.
  • Treat cached capability lists as hints, not proof of access.
  • Audit denied requests as carefully as successful privileged actions.

Authorization Consent

Authorization is not the same as consent. A user may be allowed to send an email, but the host should still ask before a model-mediated workflow sends one. Consent prompts should explain the target system, action, important arguments, and consequence in plain language. Users should not have to inspect JSON to understand what will happen.

Consent should be risk-based. Reading a public document might not require an interrupt. Posting to a shared channel, deleting a record, granting access, or spending money should require explicit approval. Repeated approvals can sometimes be batched, but only when the user can review the exact scope and cancel before execution.

  • Show the server name and action category in approval UI.
  • Display the important arguments, not just a generic warning.
  • Let users edit drafts before public or external actions.
  • Never use prior consent for a materially different target or action.
  • Store approval decisions with trace and audit metadata.

Object-Level Policy

Scopes are necessary but not enough. A token may say a caller can read tickets, but the server still needs to know which tenant, project, customer, or ticket the caller may access. Object-level authorization is where many real security bugs live.

Remote MCP authorization also requires correct discovery and token audience behavior. Clients should learn protected resource metadata, request tokens for the intended MCP server resource, use secure flows such as PKCE where required, and avoid accepting tokens issued for another resource. These details prevent confused-deputy and token misuse problems.

Authorization should happen more than once. Discovery filtering decides which capabilities appear. Invocation authorization decides whether this caller can use this capability right now. Backend authorization decides whether the underlying data system permits the exact operation. Repeating checks may feel redundant, but each layer catches a different class of mistake.

Finally, design denial behavior carefully. A denial should be clear enough for the host and user to understand next steps, but not so detailed that it reveals hidden resource names, policy internals, or tenant information.

  • Combine scopes with tenant and object-level checks.
  • Use protected resource metadata and resource indicators for remote auth.
  • Authorize discovery, invocation, and backend access separately.
  • Log denials with reason codes while keeping user-facing errors safe.

Build an Authorization Matrix

Write an authorization matrix for one remote MCP server. Rows are capabilities; columns are scopes, tenant checks, object checks, approval needs, and audit requirements. This makes it obvious where a simple scope is not enough.

Then simulate a user whose role changes during a session. Discovery may have shown a capability earlier, but invocation must still check current access. This exercise reinforces why authorization must happen at multiple layers.

  • Build a capability authorization matrix.
  • Repeat checks at invocation time.
  • Test stale discovery and role-change scenarios.

Role-Change Test

For sensitive systems, review authorization decisions with sample identities from different tenants and roles, not only with an administrator token.

Client Registration Choices

For remote servers, the stable specification supports pre-registered clients, recommends Client ID Metadata Documents when the authorization server advertises support, and retains Dynamic Client Registration as a fallback for compatible deployments. A client should not assume that one registration mechanism works everywhere.

Client ID Metadata Documents use an HTTPS URL as the client identifier. The authorization server fetches the document, verifies that its `client_id` exactly matches the URL, validates redirect URIs, and caches it according to HTTP policy. This makes registration portable without handing every authorization server a shared static secret.

Regardless of registration method, clients must use protected resource metadata to discover authorization servers and include the MCP server resource indicator in authorization and token requests. These controls reduce token misdirection and confused-deputy risk.

  • Prefer pre-registration when both parties have an established relationship.
  • Use metadata documents only when the authorization server advertises support.
  • Keep Dynamic Client Registration as a supported fallback, not an assumption.
  • Validate redirect URIs and resource indicators exactly.

Remote Authorization Chain

For HTTP deployments, the MCP server acts as an OAuth protected resource. Clients discover protected-resource metadata, locate authorization-server metadata, request a token for the intended resource, and send it to that MCP endpoint. A token issued for another audience must not be accepted merely because its signature is valid.

Use `WWW-Authenticate` challenges to communicate authorization metadata or incremental scope needs without turning every denial into a generic login loop. Public clients use PKCE where required, redirect URIs require exact validation, and tokens stay out of URLs and logs. The MCP server must not pass a client token through to an unrelated downstream service.

Transport authorization establishes who may reach the server; per-capability, tenant, object, and side-effect checks still run for every request. Filter discovery for usability, but never rely on a hidden tool as the enforcement mechanism.

  • Validate issuer, audience or resource, expiry, and required scopes.
  • Keep MCP tokens separate from downstream service credentials.
  • Support scope upgrades without granting unrelated authority.
  • Repeat object-level checks at execution time.

Authorization Flow Examples

Scope and Tenant Enforcement

Discovery and invocation should apply the same trusted authorization context.

Scope and Tenant Enforcement
Authenticated subject: user-42
Tenant: tenant-a
Scopes: policies:read

tools/list:
  include search_policies
  omit update_policy

tools/call search_policies:
  verify policies:read
  constrain query to tenant-a
  emit audit event
  • Unauthorized capabilities are hidden during discovery.
  • Invocation repeats authorization instead of trusting prior discovery.
  • Tenant filtering belongs in the backend query path.
Before you move on

Authorization Review

4 checks
  • Authenticate remote callers with real credentials.
  • Use protected resource metadata and standard OAuth discovery patterns.
  • Filter visible capabilities when appropriate.
  • Enforce authorization again inside each sensitive call path.

Authorization Questions

Usually no, but it still needs trust review, local permission thinking, and server-side validation.

No. They should be explicit enough for operators and hosts to distinguish denial from server malfunction, while remaining safe for users.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.