Skip to content

Auth & security

The DFL MCP never has its own “god mode” view of the data. Every request runs as you. This page explains how that works so you know exactly what an AI assistant can — and can’t — do on your behalf.

  1. Your DFL login. dfl-auth login prompts for your DFL email and password. Supabase returns a JWT access token and a refresh token.

  2. Bearer on every call. Your client sends Authorization: Bearer <access_token> with each MCP request. The endpoint validates the JWT’s signature and expiry.

  3. Per-session Supabase client. The endpoint builds a Supabase client using your JWT for the lifetime of that session — not a service key. So every read and write is executed with your identity.

  4. RLS decides. PostgreSQL Row-Level Security policies and your IAM role determine which rows you can see and which mutations you can make.

dfl-auth login ──▶ DFL email/password (Supabase) ──▶ JWT (access + refresh)
│
client ── Authorization: Bearer <JWT> ──▶ MCP endpoint ─┤
▼
Supabase client bound to YOUR JWT
▼
RLS + your IAM role = what you can do

Use your existing global DFL login. OpenPencil accepts the same current Supabase user JWT as the other fleet MCPs. It does not require a separate account or a token collected from a browser session.

If this PC does not have the global DFL login yet, configure the client once:

Terminal window
npx @devfellowship/dfl-auth configure
npx @devfellowship/dfl-auth login

Use your own DFL email and password in the CLI prompts. The current login prompt shows the password while you type; use a private terminal. These commands keep the existing global human workflow under ~/.dfl-mcp/.

Load the current global JWT into the client environment

Section titled “Load the current global JWT into the client environment”

The existing global login stores access_token in ~/.dfl-mcp/credentials.json. Load that token into DFL_MCP_JWT when you start your MCP client. The command below reads the existing credential in memory; it does not print it or create another credential file.

On macOS, Linux or WSL, in Bash or Zsh:

Terminal window
export DFL_MCP_JWT="$(node -e 'const fs=require("node:fs");const path=require("node:path");const os=require("node:os");const c=JSON.parse(fs.readFileSync(path.join(os.homedir(),".dfl-mcp","credentials.json"),"utf8"));process.stdout.write(c.access_token);')"
codex
# Or run claude instead.
unset DFL_MCP_JWT

On Windows PowerShell:

Terminal window
$credentialPath = Join-Path ([Environment]::GetFolderPath("UserProfile")) ".dfl-mcp/credentials.json"
$env:DFL_MCP_JWT = (Get-Content -Raw $credentialPath | ConvertFrom-Json).access_token
try {
codex
# Or run claude instead.
} finally {
Remove-Item Env:DFL_MCP_JWT -ErrorAction SilentlyContinue
}

The configuration below stores only the environment reference. Preserve any fleet servers that are already configured. Configure each endpoint once in global user scope, so the connection is available across your projects. Each human uses their own global DFL login; scope does not grant extra access.

Terminal window
codex mcp add openpencil --url https://openpencil.devfellowship.com/mcp --bearer-token-env-var DFL_MCP_JWT

This stores the variable name in the user’s global Codex MCP configuration. Start Codex from the terminal that holds the current DFL_MCP_JWT.

Terminal window
claude mcp add --transport http --scope user --header 'Authorization: Bearer ${DFL_MCP_JWT}' -- openpencil https://openpencil.devfellowship.com/mcp

The single quotes preserve the literal reference in Bash, Zsh and PowerShell. User scope makes the connection available in all your projects. Start Claude Code with DFL_MCP_JWT in its environment and check /mcp.

The client should call list_projects on OpenPencil to confirm access. Then follow the native canvas tool-call guide or the Portuguese first-interaction tutorial. OpenPencil Desktop and extra skills are optional for this flow.

The same JWT can authenticate multiple fleet endpoints. Each endpoint has its own MCP transport session. Browser SSO does not automatically authenticate a separate MCP transport. OpenPencil currently requires the bearer token and does not offer MCP OAuth login or automatic client-side token refresh.

Client references: Claude Code global scope and headers and Codex MCP configuration.

OpenPencil stores canonical FIG documents on its resident service volume. It verifies the same caller JWT, then applies project ownership and current IAM; its document bytes are not rows in a Supabase table.

Because the MCP acts as you under RLS:

  • You see your data and anything your role is allowed to read.
  • You can mutate only what your role permits.
  • A 403 Forbidden means your permissions don’t allow it — the MCP is faithfully enforcing your access, not malfunctioning.
PathContentsNotes
~/.dfl-mcp/project.jsonSupabase project configWritten by dfl-auth configure
~/.dfl-mcp/credentials.jsonaccess_token, refresh_token, expires_atWritten by dfl-auth login; auto-refreshed

Access tokens are short-lived by design. Refresh without re-doing the browser login:

  • CLI: npx @devfellowship/dfl-auth refresh
  • JS/TS: getValidAccessToken() from @devfellowship/dfl-auth auto-refreshes

The OpenPencil endpoint does not expose /auth/refresh. Renew your shared global DFL credential, then restart the client with the updated environment variable.

A future expiry does not prove a live session

Section titled “A future expiry does not prove a live session”

The current dfl-auth status command checks the stored expiry time only. A revoked session can still display Active with hours remaining. The current login and refresh commands can also skip renewal while that time is valid.

If a fleet endpoint returns 401, obtain a fresh global login:

Terminal window
npx @devfellowship/dfl-auth logout
npx @devfellowship/dfl-auth login

logout removes the local stored credential; it does not revoke every existing session. login then prompts for your DFL email and password. Reload the new access_token into DFL_MCP_JWT and restart the MCP client. Existing client processes and manually copied headers keep their old token until you update them.

Confirm recovery with an authenticated tool call, such as OpenPencil’s list_projects. A stored expiry time, configuration entry or HTTP status alone does not establish the caller’s usable session. A new global DFL email/password login restored OpenPencil access in the human review on 7 October 2026.

  • Fleet MCP endpoints use HTTPS.
  • MCP calls require the current caller’s credential.
  • Keep actual tokens out of client configuration, prompts, screenshots and shared links.
  • OpenPencil authorizes the project owner or a current global IAM level of at least 80.