> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heymcp.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> What protects your tunnel today, and what doesn't exist yet.

By default a HeyMCP tunnel is **open**. Anyone with the URL can reach your MCP
server. That's usually what you want while you're developing — it's why adding
a connector is a paste, not a credential dance — but it's worth being deliberate
about.

## The bearer token

```bash theme={null}
heymcp share localhost:8000 --bearer s3cret
```

Now the edge requires `Authorization: Bearer s3cret` on every request and
answers **401** with JSON-RPC code `-32004` without it.

You can pass it through the environment instead, which keeps it out of your
shell history:

```bash theme={null}
export HEYMCP_BEARER=s3cret
heymcp share localhost:8000
```

### What the edge does with it

<Steps>
  <Step title="Compares it in constant time">
    So the comparison can't be timed to guess the token character by character.
    The scheme (`Bearer`) is matched case-insensitively; the token itself must
    match exactly.
  </Step>

  <Step title="Strips the header">
    **Always** — whether it matched or not. Your local server never sees the
    `Authorization` header, so a token can't leak into your application logs or
    get mistaken for one of your own credentials.
  </Step>

  <Step title="Forwards, or refuses">
    A match forwards the request. Anything else — wrong token, missing header, a
    `Basic` credential instead of a `Bearer` one — is a 401.
  </Step>
</Steps>

The token is never stored. HeyMCP records only that the tunnel *required* one,
which is why the inspector can tell you a session was protected but can't tell
you the value.

### Which clients can send one

| Client        | Can send a static bearer                                 |
| ------------- | -------------------------------------------------------- |
| Claude Code   | Yes — `--header "Authorization: Bearer …"`               |
| Cursor        | Yes — a `headers` block in `mcp.json`                    |
| VS Code       | Yes — a `headers` block, ideally with a prompted `input` |
| Gemini CLI    | Yes — a `headers` block in `settings.json`               |
| ChatGPT       | **No** — its auth modes are OAuth, No Auth or Mixed      |
| Grok          | Depends on what the connector dialog offers              |
| **Claude.ai** | **No** — there is no header field, and it fails silently |

<Warning>
  Using `--bearer` locks out both Claude.ai and ChatGPT. With Claude.ai it does so
  with no error message anywhere. If either is your target, share without it.
</Warning>

## OAuth

**HeyMCP is not an OAuth authorization server.** There is no `/authorize`, no
`/token`, no dynamic client registration and no consent screen. If you're
looking for HeyMCP to add OAuth in front of an unauthenticated local server,
that doesn't exist today.

What *does* work is your own server's OAuth. The tunnel forwards
`/.well-known/*` by default — including
`/.well-known/oauth-authorization-server` and
`/.well-known/oauth-protected-resource` — so if your MCP server implements the
OAuth side of the MCP spec, clients discover and use it through the tunnel
exactly as they would against a directly-hosted server.

That includes ChatGPT's OAuth and Mixed modes: those are satisfied by your
server, not by HeyMCP.

## Choosing an approach

<CardGroup cols={2}>
  <Card title="No auth" icon="lock-open">
    The default. Right for a short-lived tunnel while you're actively working,
    and required if Claude.ai or ChatGPT is the client. The URL is unguessable
    but not secret.
  </Card>

  <Card title="--bearer" icon="key">
    Right for a tunnel you leave running, a shared demo, or anything touching
    real data. One flag, no server code — but Claude.ai and ChatGPT can't send
    it.
  </Card>

  <Card title="Your own OAuth" icon="shield-check">
    Right when the MCP server is heading for production anyway. Implement it in
    your server; the tunnel passes discovery through untouched.
  </Card>

  <Card title="Narrow the paths" icon="filter">
    Not authentication, but related: by default only `/mcp*` and
    `/.well-known/*` are reachable at all. See
    [What is exposed](/security/what-is-exposed).
  </Card>
</CardGroup>

## Your HeyMCP account

Separate from all of the above:

* **Sign-in is GitHub only.** No passwords to leak.
* **The CLI holds a token**, stored in `~/.config/heymcp/config.json` with mode
  `0600`. It's shown once and stored hashed server-side. Roll it from your
  profile page if it's ever exposed.
* **A session belongs to exactly one account.** There is no team model, so
  nobody else can read your timeline.

See [Signing in](/account/signing-in).
