Skip to content

Practical Auth for Functions: API Keys, Signatures, Console Guard, and Safe Defaults

Verified status as of March 28, 2026. Runtime note: FastFN auto-installs function-local dependencies from requirements.txt / package.json; host runtimes are required in fastfn dev --native, while fastfn dev depends on a running Docker daemon.

Why this article matters

Security often gets added late, and then teams bolt on too much complexity.

This guide gives a practical baseline you can deploy now: - function-level auth, - strict method and body limits, - console safety, - webhook signature verification pattern.

It is written for builders who want production-safe defaults without enterprise overhead.

Quick docs map

Security layers in fastfn

  1. Gateway policy from fn.config.json.
  2. Function-level auth logic inside your handler.
  3. Console/UI access gates.

You usually need all three.

Layer 1: Lock the gateway policy first

Minimal secure fn.config.json example:

{
  "timeout_ms": 1500,
  "max_concurrency": 5,
  "max_body_bytes": 131072,
  "invoke": {
    "methods": ["POST"],
    "summary": "Signed webhook receiver"
  }
}

Effects: - non-POST calls fail with 405, - huge payloads fail with 413, - runaway parallel requests fail with 429.

Layer 2: Add function-level API key auth

Node example:

exports.handler = async (event) => {
  const headers = event.headers || {};
  const apiKey = headers['x-api-key'] || headers['X-API-Key'];
  const expected = (event.env || {}).MY_API_KEY;

  if (!expected || apiKey !== expected) {
    return {
      status: 401,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ error: 'unauthorized' })
    };
  }

  return {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ok: true })
  };
};

Store secret in fn.env.json:

{
  "MY_API_KEY": { "value": "set-me", "is_secret": true }
}

Layer 3: Signature auth for external webhooks

For Stripe/GitHub-like integrations, use signature verification on raw body.

Pattern: 1. read raw body from event.body, 2. compute HMAC with shared secret, 3. compare to signature header, 4. reject mismatch with 401.

This is stronger than static API keys for callbacks.

Layer 4: Protect console and admin APIs

Recommended platform env:

FN_UI_ENABLED=1
FN_CONSOLE_LOCAL_ONLY=1
FN_CONSOLE_WRITE_ENABLED=0
FN_ADMIN_TOKEN=<strong-random-token>

Meaning: - UI accessible, - local-only by default, - write actions disabled unless admin token is present.

Verification checklist (copy/paste)

  1. Missing API key returns 401.
  2. Wrong method returns 405.
  3. Oversized payload returns 413.
  4. Invalid signature returns 401.
  5. Unauthenticated console write returns 403.

Example curl checks

Unauthorized:

curl -i -sS -X POST http://127.0.0.1:8080/secure-webhook

Wrong method:

curl -i -sS http://127.0.0.1:8080/secure-webhook

Expected responses should include 401 and 405 respectively.

Common mistakes

  • Putting secrets in source code instead of fn.env.json.
  • Exposing console writes from remote networks.
  • Leaving sensitive endpoints open to GET.
  • Ignoring max_body_bytes on webhook handlers.

Practical baseline profile

Use this as your default for external-facing functions: - methods restricted to minimum required, - body limit under 256 KB unless necessary, - low concurrency for expensive external APIs, - local-only console with token for privileged actions.

Key takeaway

Start with gateway limits and add handler-level auth only where identity actually matters. That combination blocks bad requests early and keeps your auth code short enough to review and test.

What to keep in mind

  • Put secrets in fn.env.json, not in source files or copied curl payloads.
  • Restrict methods and body size before the request reaches your handler.
  • Treat public function routes and console/admin endpoints as separate security surfaces.

Which auth pattern fits which job

  • API keys work well for service-to-service calls and private webhooks.
  • Signed payload verification is a good fit when the provider already sends a signature header.
  • JWT verification makes sense when another service is responsible for login and token issuance.

See also

JWT issuance and verification pattern

Recommended architecture:

  1. issue JWT in a dedicated auth service
  2. verify signature + expiration in FastFN function helper
  3. map claims (sub, scope, aud) to local permissions

Quick verification example:

curl -i 'http://127.0.0.1:8080/private' -H 'authorization: Bearer <jwt>'

Expected:

  • invalid/expired token -> 401
  • missing scope -> 403
  • valid token and scope -> 200
Last reviewed: March 28, 2026 · Docs on fastfn.dev