Stopped n8n from holding real API credentials entirely — proxy boundary pattern (Lark + OpenAI, finance workflow)
Been running invoice OCR + Lark approval automation on n8n for a few months. The workflow itself works fine, but credential hygiene was a mess. Finally solved it structurally — sharing the pattern.
The core problem:
Export workflow JSON → real sk-proj-... and Lark tenant_access_token travel with it. Hand it to a teammate, put it in version control, or give it to an AI coding tool — credentials leak. Even without hardcoding, the "fetch token first" node pattern means re-running any branch in isolation breaks the chain.
How the pattern works
1. Register each API as a named service in a proxy layer
- Real credentials loaded from local env at registration time
- Proxy holds them — n8n never sees them
2. Replace every direct API call in n8n with a proxy URL
https://<proxy>/s/api-lark-bot/open-apis/...instead of calling Lark directlyhttps://<proxy>/s/openai/v1/chat/completionsinstead of OpenAI directly
3. Store the proxy token as an n8n Header Auth Credential
- Workflow JSON only carries credential
id, never the real token - One rotating token for all downstream APIs
4. Delete the get-lark-token prefetch node
- Token refresh happens inside the proxy layer
- n8n doesn't know or care about Lark's 2h TTL
5. Grep before every commit
- Two-layer check: redaction script + grep scan for known prefixes (
sk-,cli_,Bearer) - Catches the case where someone pastes a token directly into a node header
What was harder than expected
- The proxy token itself can still leak into JSON if you forget to use n8n's Credential store and paste it directly into a header — same problem, one layer up
- Lark's
tenant_access_tokenrefresh timing: if the proxy caches the token and it expires mid-workflow, you get a99991663error. An IF node that retries once is enough - PDF → GPT-4o Vision requires image conversion first —
pdf-to-pngisn't in n8n's default Code node sandbox, needNODE_FUNCTION_ALLOW_EXTERNAL=pdf-to-png - Getting the proxy URL format right for path-auth APIs (Lark's endpoint structure is not RESTful in the obvious way)
What I like about this setup
- AI tools can read and edit workflow JSON safely — no credentials to leak
- Month-end audit is one place: proxy call log, not Lark + OpenAI + n8n stitched by hand
- Token rotation happens once at the proxy, not across every workflow that uses the API
- ~3 hours/week recovered on the finance side (teammate no longer forwards me invoices to type in manually)
Workflow (for anyone curious)
Four key nodes: Form Trigger (invoice upload) → GPT-4o OCR via proxy → human review step → Create Lark Approval via proxy.
Happy to share specifics on any node if useful.