Skip to main content

Overview

You may want employees to use a subset of a third-party production API, such as Stripe, for a narrow set of tasks. Without Formal, this usually means giving them a production API key with broader permissions than you want to allow. That key then sits on their laptop, in a .env file or shell profile. With Formal, you can use the and a to:
  • Keep the API key off employee laptops. Only the Connector holds it.
  • Let employees make authenticated requests to the Stripe API without a credential.
  • Write fine-grained policies against every request between the laptop and Stripe.
This guide uses curl on macOS.

How It Works

  1. The Formal Endpoint on macOS intercepts curl requests to api.stripe.com with a network rule.
  2. The Endpoint forwards them to the Connector with the developer’s Formal identity.
  3. A on the Stripe injects Authorization: Bearer <STRIPE_API_KEY>.
  4. Stripe receives the real key. The laptop never does.
Clients keep calling https://api.stripe.com. You do not change base URLs.

Prerequisites

  • on macOS with Transparent Mode enabled
  • A deployed the Endpoint can reach
  • Stripe API Key

1. Store the key on the Connector

Set the key as the STRIPE_API_KEY environment variable on the Connector.

2. Create the Stripe resource

  1. Navigate to Resources and click Create Resource
  2. Set Technology to HTTP
  3. Set Name to stripe
  4. Set Hostname to api.stripe.com and Port to 443
  5. Save the resource
  6. Add a TLS configuration to the resource and select Verify Full
Verify Full makes the Connector check the certificate chain and hostname of api.stripe.com before it sends the API key.

3. Add a Native User for the key

The Native User tells the Connector to set Authorization: Bearer <key> on every Stripe request. It replaces any Authorization header the client sent.
  1. Open the stripe resource and select Authentication
  2. Click Add User and select HTTP Bearer
  3. Set Label to stripe-api-key
  4. Choose Static, set the header to Authorization, and choose Environment Variable
  5. Enter STRIPE_API_KEY and click Create
  6. Copy the Native User ID from its action menu
  7. Under Default Native User, paste that ID as the CEL expression and click Save
Set a default Native User. Without one, HTTP resources forward requests without an injected key, and Stripe returns 401.
See Native Users for all selection fields. Verify: The stripe-api-key Native User appears under Native Users with type HTTP Bearer and source STRIPE_API_KEY.

4. Make Stripe reachable through the Connector

  1. Open your Connector and select Listeners
  2. Create a listener on an available port, such as 443. Port 8080 is reserved for health checks.
  3. Open the listener, click New Rule, set the type to Resource, and select stripe
Verify: stripe appears under the Connector’s Reachable Resources.

5. Forward Stripe traffic to the Connector

Create a network rule that intercepts curl requests to api.stripe.com and forwards them to the Connector. Match curl by its code signing identifier in pre_tcp, and check the hostname in pre_tls. Find the identifier with codesign:
  1. Navigate to Network Rules
  2. Create a rule named stripe-curl
  3. Paste the CEL below
  4. Save the rule and set it to Active
Forward to Connector must be true. Without it, the Endpoint evaluates the request locally, and no Native User injects the key.

6. Restrict Stripe requests with a policy

The default Native User injects the key into every request that reaches the stripe resource. Add a policy that blocks every Stripe request except the ones your developers need. This example lets the payments-engineers group read balances, charges, and customers. It blocks all other Stripe requests, including writes and requests from other users.
  1. Navigate to Policies
  2. Click Create Policy
  3. Set name to stripe-read-only and add a description
  4. Paste the Rego below into the editor
  5. Click Create Policy to save
Adjust allowed_paths, the methods, and the group to match what your developers need. Find Stripe paths in the Stripe API reference. See HTTP object for all request fields. Verify: A GET /v1/balance from a payments-engineers member succeeds. A POST /v1/refunds returns the Formal block message.

7. Call Stripe without a key

Remove Stripe keys from .env files, shell profiles, and CLI configs on the laptop. Then call Stripe with curl and no key:
Verify:
  1. Open Logs and filter on the stripe resource
  2. Confirm the request shows the developer’s Formal identity
  3. Confirm the response status is 200

Troubleshooting

Possible causes:
  • Transparent Mode is off
  • The network rule is in Draft
  • curl is not /usr/bin/curl, for example Homebrew curl, so its code signing identifier differs
Fix:
  1. Run formal transparent-proxy status
  2. Set the stripe-curl network rule to Active
  3. Run codesign -dvv $(which curl) and use its Identifier in pre_tcp

Next Steps

Stripe API Keys

Manage Stripe API keys

Native Users

Select credentials by identity or with hooks

HTTP Resources

Write policies for HTTP traffic

Network Rules

Choose which traffic the Endpoint intercepts

Encrypt MCP OAuth Tokens

Keep OAuth tokens encrypted on the device