---
title: Authentication Demo Servers
sidebarTitle: Demo Servers
slug: authentication/demo-servers
icon: terminal
description: Run the Nx sample servers that showcase public, transparent, and orchestrated authentication modes.
keywords: ['frontmcp', 'mcp', 'model context protocol', 'authentication', 'auth', 'oauth', 'security', 'demo', 'examples', 'typescript']
---

FrontMCP bundles three ready-to-serve authentication demos under `apps/e2e/**`. Each project runs the same Notes + Tasks apps but wires a different auth mode, transport policy, and consent experience so you can validate clients before touching your own code.

## Projects at a glance

| Project                 | Mode                   | Default port | Highlights                                                                      | Serve command                                     |
| ----------------------- | ---------------------- | ------------ | ------------------------------------------------------------------------------- | ------------------------------------------------- |
| `demo-e2e-public`       | `public`               | `3100`       | Anonymous sessions with scoped tools, Streamable HTTP + JSON fallback           | `PORT=3100 yarn nx serve demo-e2e-public`         |
| `demo-e2e-orchestrated` | `orchestrated` (local) | `3121`       | Stateful sessions, consent UI, incremental auth controls                        | `PORT=3121 yarn nx serve demo-e2e-orchestrated`   |
| `demo-e2e-transparent`  | `transparent`          | `3109`       | Proxies tokens to a remote IdP while keeping local transport policies           | `PORT=3109 yarn nx serve demo-e2e-transparent`    |

<Note>
All commands assume `yarn install` has already been run at the repo root. The serve target runs the prebuilt `dist/.../main.js`, so it does **not** forward an `--port` flag — set the port via the `PORT` environment variable (`PORT=<n> yarn nx serve <project>`).
</Note>

## Run a demo locally

<Steps>
<Step title="Pick a project">
Decide which auth mode to explore (`demo-e2e-public`, `demo-e2e-transparent`, or `demo-e2e-orchestrated`).
</Step>
<Step title="Configure environment">
Transparent mode needs an upstream IdP. Export `IDP_PROVIDER_URL` and `IDP_EXPECTED_AUDIENCE` before serving:

```bash
export IDP_PROVIDER_URL="https://auth.example.com"
export IDP_EXPECTED_AUDIENCE="https://api.example.com"
```

</Step>
<Step title="Serve the project">
Run `PORT=<port> yarn nx serve <project>` and wait for the `Listening on` log. Requests are available at `http://localhost:<port>`. The serve target runs the prebuilt bundle and does not accept a `--port` flag, so the port must come from the `PORT` environment variable.

<Check>
`curl http://localhost:<port>/health` returns a JSON body like `{ "status": "ok", "server": { ... }, "uptime": ... }` when the server is ready.
</Check>
</Step>
</Steps>

---

## demo-e2e-public: instant anonymous access

```ts title="apps/e2e/demo-e2e-public/src/main.ts"
@FrontMcp({
  info: { name: 'Demo E2E Public', version: '0.1.0' },
  apps: [NotesApp],
  auth: {
    mode: 'public',
  },
});
```

- Exercises the `auth.publicAccess` path without any login UI.
- Uses framework defaults for transports (Streamable HTTP + SSE + JSON), suitable for smoke tests.

<Tip>
Use this project with `@frontmcp/testing` when you want fast, anonymous fixtures that still cover transport-level behavior.
</Tip>

---

## demo-e2e-orchestrated: built-in OAuth server

```ts title="apps/e2e/demo-e2e-orchestrated/src/main.ts"
@FrontMcp({
  info: { name: 'Demo Orchestrated Auth', version: '0.1.0' },
  apps: [NotesApp, TasksApp],
  auth: {
    mode: 'local',
    consent: {
      enabled: true,
      groupByApp: true,
      showDescriptions: true,
      allowSelectAll: true,
      requireSelection: true,
      rememberConsent: true,
    },
    tokenStorage: 'memory', // Use { redis: ... } in production
    allowDefaultPublic: false,
    anonymousScopes: ['anonymous'],
  },
  transport: {
    sessionMode: 'stateful',
    protocol: {
      sse: true,
      streamable: true,
      json: true,
      stateless: false,
      legacy: false,
      strictSession: false,
    },
  },
});
```

- Spins up the full OAuth 2.1 stack (authorization code + PKCE) entirely inside FrontMCP.
- Shows the consent UI grouping tools by app, plus incremental auth defaults.
- Uses the same transport defaults documented in [Transport controls](/frontmcp/servers/server#transport) so you can compare behavior with production builds.

<Warning>
The demo login accepts any email address. Replace it with a real IdP before exposing the flow to users.
</Warning>

---

## demo-e2e-transparent: pass-through tokens

```ts title="apps/e2e/demo-e2e-transparent/src/main.ts"
@FrontMcp({
  auth: {
    mode: 'transparent',
    provider: process.env.IDP_PROVIDER_URL!,
    providerConfig: {
      dcrEnabled: false,
    },
    expectedAudience: process.env.IDP_EXPECTED_AUDIENCE!,
    requiredScopes: [],
    allowAnonymous: false,
  },
});
```

- Validates upstream JWTs while reusing the same transport policies. (Transparent mode has no `consent` option — the consent UI is a `local`/`remote`-mode feature.)
- Demonstrates how to forward-declare an IdP without shipping secrets—set `IDP_PROVIDER_URL`/`IDP_EXPECTED_AUDIENCE` per environment.
- Keeps anonymous access off so every tool call requires a verified token.

<Note>
If your IdP exposes a JWKS file, frontload the URL in `providerConfig.jwksUri` to skip metadata discovery during tests.
</Note>

---

## Test with @frontmcp/testing

You can point the Jest fixtures at any demo by spinning it up through the built-in `TestServer` helper:

```ts title="demo-public.e2e.ts"
import { test, expect, TestServer } from '@frontmcp/testing';

let serverProcess;

test.beforeAll(async () => {
  serverProcess = await TestServer.startNx('demo-e2e-public', { port: 4001 });
});

test.afterAll(async () => {
  await serverProcess?.stop();
});

test.use({
  server: serverProcess?.info.baseUrl ?? 'http://localhost:4001',
  transport: 'streamable-http',
});

test('lists demo tools', async ({ mcp }) => {
  const tools = await mcp.tools.list();
  expect(tools).toContainTool('create-note');
});
```

Pair this with the [Transport controls reference](/frontmcp/servers/server#transport) to mirror the exact transports your production server exposes.

---

## What to read next

<CardGroup cols={2}>
  <Card title="Authentication Modes" icon="layer-group" href="/frontmcp/authentication/modes">
    Understand when to reach for public, transparent, or orchestrated auth.
  </Card>
  <Card title="Transport controls" icon="server" href="/frontmcp/servers/server#transport-controls">
    Dive deeper into Streamable, stateful, and stateless HTTP settings.
  </Card>
</CardGroup>
