Outcome: You can encrypt OAuth tokens so clients only see token ciphertexts instead of plaintext Bearer tokens. This example focuses on Notion MCP OAuth, but this approach should extend to any OAuth DCR flow.
Prerequisites: The Formal Endpoint transparent proxy on macOS. Use Secure Enclave encryption on the Endpoint, or forward traffic to a with token encryption.
Overview
Notion MCP (https://mcp.notion.com/mcp) issues OAuth tokens from the same host (POST /token). Clients then send Authorization: Bearer <token> on MCP calls.
Formal can encrypt those tokens in two places:
In both cases:
- An encrypt encrypts
access_tokenandrefresh_tokenon the OAuth token response. - The MCP client stores
formalsealed:v1:.... - A decrypt policy decrypts
Authorizationbefore Notion MCP sees the request.
https://mcp.notion.com. You do not rewrite the MCP URL.
Policies
These policies apply whether encryption runs on the Endpoint or the Connector.Encrypt OAuth tokens
- Web Console
- Terraform
- Navigate to Policies
- Click Create Policy
- Set name to
notion-mcp-encrypt-oauth-tokensand add a description - Paste the Rego below into the editor
- Click Create Policy to save
Decrypt Authorization on MCP requests
- Web Console
- Terraform
- Navigate to Policies
- Click Create Policy
- Set name to
notion-mcp-decrypt-authorizationand add a description - Paste the Rego below into the editor
- Click Create Policy to save
Bearer formalsealed:v1:... becomes Bearer <plaintext> for Notion. Values without an encrypted token pass through unchanged.
Encrypt on the Formal Endpoint (Secure Enclave)
On macOS, the Formal Endpoint can encrypt and decrypt tokens with the device Secure Enclave. Traffic stays on the Endpoint. You do not set Forward to Connector. Create a network rule that matches Notion MCP. No Connector listener or KMS key is required for this path.- Web Console
- Terraform
- Navigate to Network Rules (or use Network Rules in the Desktop App)
- Create a rule named
notion-mcp-endpoint - Match hostname
mcp.notion.comon the pre-TLS condition - Leave Forward to Connector unset / false
- Save the rule
- Enable the transparent proxy:
formal transparent-proxy enable - Confirm the network rule is Active
- Complete Notion MCP OAuth. Confirm
access_tokenstarts withformalsealed:v1:
Endpoint
encrypt is macOS-only. See Encrypt & Decrypt.Encrypt on the Connector
To encrypt tokens on the Connector, forward Notion MCP through a Connector and attach a token encryption key (formal_connector_token_encryption_key). Without that KEK, Connector encrypt fails closed and blocks the OAuth response.
Set up the following:
- An MCP resource for
mcp.notion.com - A Connector listener and listener rule so the resource is reachable
- A token encryption key on the Connector (cloud KMS KEK)
- A network rule with
forward_to_connectorset totrue
- Web Console
- Terraform
- Create an MCP resource for hostname
mcp.notion.comon port443 - On your Connector, add a listener on port
443and a listener rule that points at that resource - Attach a token encryption key to the Connector
- Create a network rule named
notion-mcp-connectorthat matchesmcp.notion.comand sets Forward to Connector
- Notion MCP appears under the Connector’s Reachable Resources
- The Connector has a token encryption key configured
- The network rule is Active with Forward to Connector
- Complete Notion MCP OAuth. Confirm encrypted
formalsealed:v1:tokens and successful MCP tool calls
Add Notion MCP and complete OAuth
After policies and routing are in place, add Notion MCP as usual. Formal does not change Dynamic Client Registration (DCR) or the OAuth browser flow.- Add the Notion MCP server at
https://mcp.notion.com/mcp. For Claude Code:
- Complete DCR and OAuth when the client prompts you.
mcp.notion.com, so Claude Code still uses the real Notion URL. Encrypted tokens are what the client persists after /token.
Verify end to end
- Keep the MCP client pointed at
https://mcp.notion.com/mcp. - Finish OAuth through Claude Code (or your MCP client).
- Call a Notion MCP tool. The call should succeed.
- Confirm encrypt on
POST /tokenand decrypt on later MCP requests in Formal logs.
Inspect encrypted tokens in Claude Code (macOS)
Claude Code stores MCP OAuth credentials in the macOS Keychain. After OAuth completes, read that entry and confirm Notion tokens are encrypted:notion|<id>). Both accessToken and refreshToken should start with formalsealed:v1::
accessToken is a raw Notion token instead of formalsealed:v1:..., encrypt did not run on POST /token (check the network rule, policies, and Connector token encryption key if you use the Connector path).
Keychain entry names can vary by Claude Code version. If the command finds no password, search Keychain Access for Claude credentials or re-run OAuth after confirming the transparent proxy is enabled.
Troubleshooting
Token response is not encrypted
Token response is not encrypted
Possible causes:
- Transparent proxy or network rule is inactive
- Connector path missing
forward_to_connectoror KEK - Policy path does not match
POST /token
- Run
formal transparent-proxy status - Set the network rule to Active
- For Connector encryption, confirm the token encryption key, listener rule, and
forward_to_connector
Next Steps
MCP Resources
Proxy and govern MCP traffic
Token Encryption
Configure the Connector KMS KEK
Encrypt & Decrypt
Full action reference
Desktop App
Enable the transparent proxy