Noodle Seed
Guides

Customer auth for remote MCP clients

Connect one customer-protected MCP server to standards-based clients with OAuth discovery, DCR, PKCE, refresh tokens, and resource-bound access tokens.

Noodle Seed verifies customer access tokens and protects your MCP tools. For direct or federated OIDC, your application developer still owns the authorization server that signs users in and issues those tokens.

This boundary keeps the architecture simple:

Person or systemResponsibility
App userAdds the deployed MCP URL to a client and completes the normal sign-in and consent flow.
App developerPublishes standards-compliant OAuth discovery, registration, authorization, token, refresh, and JWKS behavior.
Noodle SeedAdvertises the configured issuer, verifies resource-bound access tokens, diagnoses readiness, and runs the tools.
MCP clientDiscovers the issuer, registers or uses a configured OAuth client, opens sign-in, refreshes tokens, and calls the MCP server.

Noodle Seed does not put an OAuth compatibility proxy in front of a direct or federated issuer. The app developer fixes the issuer once, and every standards-based remote MCP client benefits.

Choose the customer auth shape

Use a built-in adapter when your customers already sign in with one of the supported managed providers:

auth: customerAuth.firebase({
  projectId: variable('FIREBASE_PROJECT_ID'),
  apiKey: variable('FIREBASE_WEB_API_KEY'),
  authDomain: variable('FIREBASE_AUTH_DOMAIN'),
})

Use direct OIDC when one issuer protects the app:

auth: customerAuth.oidc({
  issuer: 'https://id.example.com/oauth',
  audience: 'https://acme.cloud.noodleseed.dev/support/mcp',
})

Use federated OIDC when an exact allowlist of issuers can identify customers:

auth: customerAuth.federatedOidc({
  issuers: [
    {
      issuer: 'https://id.example.com/oauth',
      audience: 'https://acme.cloud.noodleseed.dev/support/mcp',
    },
  ],
})

The rest of this guide applies to direct and federated OIDC. Built-in adapters use their managed authorization-server path.

What the app developer must publish

1. Direct RFC 8414 discovery

For an issuer with a path, OAuth clients try the path-inserted authorization-server metadata URL first.

Configured issuerRequired primary discovery URL
https://id.example.comhttps://id.example.com/.well-known/oauth-authorization-server
https://id.example.com/oauthhttps://id.example.com/.well-known/oauth-authorization-server/oauth

The primary URL must:

  • Be publicly reachable without cookies or an existing login.
  • Return HTTP 200 directly, without a 301, 302, 307, or 308 login redirect.
  • Return a JSON object.
  • Contain an issuer value that exactly matches the configured issuer.

2. Complete OAuth metadata

A minimal interoperable document looks like this:

{
  "issuer": "https://id.example.com/oauth",
  "authorization_endpoint": "https://id.example.com/oauth/authorize",
  "token_endpoint": "https://id.example.com/oauth/token",
  "jwks_uri": "https://id.example.com/oauth/jwks",
  "registration_endpoint": "https://id.example.com/oauth/register",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"]
}

The endpoints must use HTTPS. registration_endpoint is Dynamic Client Registration under RFC 7591. Remote MCP clients are public OAuth clients, so they use PKCE rather than a client secret. Support:

  • Authorization code flow.
  • PKCE with S256.
  • Public clients with token endpoint auth method none.
  • Refresh tokens, including safe rotation and revocation.
  • The exact redirect URIs submitted during registration.

3. Resource-bound access tokens

Implement the RFC 8707 resource parameter on both authorization and token requests. The resulting access token must identify the exact MCP resource URL in its aud claim.

For example:

resource=https://acme.cloud.noodleseed.dev/support/mcp
aud=https://acme.cloud.noodleseed.dev/support/mcp

Do not issue a generic token for every API. Noodle Seed rejects tokens whose issuer or audience does not match the configured customer auth and deployed MCP resource.

4. A public JWKS

jwks_uri must return HTTP 200 JSON with at least one public RSA, EC, or OKP signing key. Never publish private fields such as d, p, q, or a symmetric k.

Check before sharing

Run the read-only diagnostic against the authored server:

noodle auth doctor src/server.ts

It verifies the primary RFC 8414 route, exact issuer, endpoints, authorization-code and refresh support, PKCE, public-client support, DCR advertisement, and public JWKS. Its issuer-readiness probes send bounded GET requests only. They do not submit a registration request, create a client, or mutate the authorization server.

For machine-readable findings:

noodle auth doctor src/server.ts --json

Each finding has a stable code, level, optional issuer, message, and repair instruction. A direct or federated issuer is ready only when every required check passes.

Then deploy:

noodle deploy src/server.ts --access customers

A successful customer deploy runs the same readiness diagnostic. OAuth failures are warnings, not deploy failures, because the MCP artifact is already live and the app developer can repair the issuer independently. JSON output includes:

{
  "ok": true,
  "data": {
    "authReadiness": {
      "ready": false,
      "checks": [
        {
          "code": "oauth_metadata_discovery",
          "level": "FAIL",
          "issuer": "https://id.example.com/oauth",
          "message": "the attempted metadata URL and safe HTTP status",
          "fix": "Serve the path-inserted RFC 8414 URL directly as HTTP 200 JSON."
        }
      ]
    }
  }
}

Repair the issuer, rerun noodle auth doctor src/server.ts, and reconnect the client. You do not need to redeploy when only the external authorization server changed.

What the user experiences

When everything is ready:

  1. The user enters the deployed MCP server URL in a compatible client.
  2. The client reads protected-resource metadata and discovers the configured authorization server.
  3. The client dynamically registers a public OAuth client, or uses another standards-supported registration method.
  4. The browser opens the app's authorization page.
  5. The user signs in and grants access.
  6. The authorization server returns an authorization code bound to PKCE and the MCP resource.
  7. The client exchanges the code, stores the access and refresh tokens, and calls the MCP endpoint.
  8. Noodle Seed verifies issuer, signature, expiry, and the exact MCP audience before any tool runs.

If the client asks the user for a client ID and secret immediately, discovery or Dynamic Client Registration did not complete. That prompt is a useful compatibility fallback, but it is not the preferred customer experience.

Copy this request to the app developer

Please make our authorization server compatible with standards-based remote MCP clients. Publish the path-inserted RFC 8414 metadata URL as unauthenticated HTTP 200 JSON with the exact issuer and HTTPS authorization_endpoint, token_endpoint, jwks_uri, and RFC 7591 registration_endpoint. Support authorization code, refresh tokens, PKCE S256, public clients using token endpoint auth method none, exact registered redirect URIs, RFC 8707 resource, access-token aud equal to the exact MCP URL, and a public JWKS with no private key material. Do not redirect the metadata URL to login. Verify the result with noodle auth doctor src/server.ts; the command is read-only and will identify each remaining gap.

Client-specific notes

The OAuth contract above is host-neutral. Client features and availability change independently:

Use the clients' current official documentation when running release acceptance. A client-specific smoke is evidence for that client and date, not a permanent protocol guarantee.

On this page