An application that uses Stripe, AWS, or Twilio often receives the provider credential through a deployment secret and calls the provider directly. That is a valid design, but it is not the only one.
The application can instead authenticate to a narrow intermediary. The intermediary checks the application’s permission, applies the provider credential, and performs the requested operation. Both models are useful; they place trust, operational work, and failure modes in different places.
Direct provider access
The familiar path is:
~~~text Secret store → Application → Provider API ~~~
The application may load a key from a deployment platform, environment variable, or secrets manager. At the point of use, it possesses the provider authority. A Stripe secret key can create a PaymentIntent; an AWS identity can call the AWS actions allowed by its policy.
Direct access has real advantages:
- provider SDKs and documentation usually assume it;
- new provider operations do not wait for an intermediary to support them;
- streaming, pagination, and large transfers can use the provider’s normal path;
- there is one fewer runtime dependency;
- debugging can compare the application directly with provider documentation.
Keep the credential narrow. Do not give an application an administrator key merely because it is convenient. Prefer separate identities, short-lived credentials, workload roles, and provider-side restrictions where the provider supports them. AWS’s IAM best practices and Stripe’s restricted API keys describe provider-specific options.
Workload identity is often the simplest direct model on a cloud platform. An AWS workload role or equivalent machine identity can issue temporary credentials without putting a long-lived access key in the repository or deployment configuration. A secret manager is also sensible when the application genuinely needs the value and the team already operates one. Neither approach is a failure merely because a relay exists.
A credential boundary
The alternative path is:
~~~text Application → authenticated operation → Relay → Provider API ↑ provider credential ~~~
The application still has something sensitive: its own identity and authorization to call the relay. The difference is that it does not receive the underlying provider key. A relay can expose a narrow operation such as sending email, or preserve a provider-native request model for a selected API surface.
Moving a key from .env to a secrets manager changes delivery and storage. It does not change the trust boundary after the application has retrieved the key. A relay changes that boundary, but only if it validates operations and scopes the relay identity. An unrestricted proxy backed by a broad administrator credential simply moves the risk behind another endpoint.
Compare the boundaries
| Concern | Direct credential or workload identity | Operation relay |
|---|---|---|
| Trust boundary | Application can call the provider with granted authority | Application can call only granted relay operations |
| Blast radius | Credential compromise may expose every permitted provider action | Application compromise can abuse every granted relay operation, but should not extract the provider key |
| Provider-key rotation | Applications or secret delivery may need updating | Rotate at the relay while app identities remain separate |
| Developer and AI-tool access | Runtime credentials may enter local workspaces or processes | Provider key can remain outside those workspaces |
| Logging risk | SDK traces and debug output can expose the key or request | Relay logs still need redaction; message content may remain sensitive |
| Latency and availability | One provider hop | Application depends on relay plus provider |
| Migration effort | Usually smallest initial change | Requires an application contract, auth, monitoring, and migration |
| Debugging | Direct comparison with provider SDK/docs | Need to separate application, relay, and provider failures |
| Operational ownership | Application team owns integration and credentials | Relay owner owns capacity, supported operations, credential rotation, and availability |
| Provider coverage | Broad provider surface immediately available | Limited to the relay’s documented provider contracts |
The last row is often decisive. A relay is useful when a stable operation boundary is more valuable than broad provider coverage. It is a poor fit when the application needs every new endpoint, unusual request shape, streaming, or provider-specific SDK behavior immediately.
Authority and application compromise
A relay is not a harmless permission wrapper. If an application is compromised, an attacker may use its Gateman identity to send email, create Stripe resources, request presigned S3 operations, or perform any other capability the identity has been granted. Rate limits, environment separation, business authorization, and narrow scopes still matter.
The advantage is different: the attacker should not be able to read the underlying provider credential and reuse it against unrelated provider APIs. That only holds if the relay does not offer arbitrary credential retrieval or unrestricted forwarding under the same identity.
The application must still authorize its own user and tenant. A relay can know that an application is allowed to use stripe.use; it may not know whether a particular logged-in user may refund a particular order. Provider permissions remain authoritative, and business authorization remains application responsibility.
What rotation and debugging look like
With direct access, rotating a shared provider key may require updating every application that holds it. Workload roles reduce that burden by making credentials temporary, while a secret manager centralizes delivery and versioning.
With a relay, provider-key rotation can happen at one provider boundary while applications retain their own relay identities. That reduces distribution work, but introduces relay state: credentials, environment mappings, capability assignments, audit logs, rate limits, and deployment health all need ownership.
Debugging also changes. Direct access lets the application inspect provider request IDs, native errors, and SDK behavior in one path. A relay should preserve useful provider status and correlation information without logging credentials or full sensitive message content. When something fails, determine whether the application rejected its own input, the relay rejected the contract, the provider rejected the request, or the network outcome is uncertain.
Provider examples
Stripe is a provider-native relay within a documented transport contract. Gateman’s capability ID is stripe.use, its application scope is stripe:use, and its route is POST /stripe/request. The application submits a supported native method, /v1/ path, body, and headers. Gateman supplies the configured Stripe credential, but Stripe remains authoritative for provider permissions and the application remains responsible for tenant and business authorization.
S3 is a different operation boundary. Gateman’s capability ID is s3.use, its scope is s3:use, and its route is POST /s3/presign. The response is a presigned operation that the application or browser uses with S3. Gateman does not carry the object bytes, so the boundary controls authorization and signing without becoming a file-transfer bottleneck.
SES uses a purpose-built email contract rather than a raw SES SDK passthrough. The capability ID and scope are both email.send, and the SES route is POST /send/ses. The application supplies Gateman’s documented message shape; Gateman manages the configured provider credential and sender boundary. Development and staging capture locally, while production contacts SES.
These contracts differ because the provider operations differ. A presigned S3 URL, a native Stripe request relay, and a structured email send are not interchangeable generic proxy features.
Credential distribution is still useful
Some applications really do need the provider value. A database migration tool may need a database password; a specialized SDK may require an API token; an operator may need to configure a provider feature that a relay does not expose. In those cases, use a secret manager, deployment secret store, or workload identity appropriate to the environment.
Gateman’s generic retrieval path is the credential-distribution model. The secrets.read capability uses scope secrets:read and POST /secrets/get to return an authorized stored value to the application. Once returned, the application must protect it in memory, logs, diagnostics, and child processes just as it would any other secret. It does not create the same boundary as stripe.use, s3.use, or email.send.
See the generic secret retrieval documentation when the application needs an approved value. Do not grant retrieval merely because a provider operation would be more convenient with a reusable credential.
Latency, availability, and migration
The extra hop adds network latency and makes relay availability part of the application’s provider path. A relay should have bounded timeouts, useful error classification, capacity controls, and a plan for provider responses that are uncertain. The application should not blindly retry mutations just because the intermediary returned a transport error.
Migration is usually incremental. Start with one operation whose input and result are clear, preserve the application’s existing business logic, and compare direct and relayed behavior in a nonproduction environment. Keep direct access available until logging, errors, retries, and operational ownership are understood. A relay that makes debugging impossible is not a meaningful security improvement.
Choosing the boundary
Use direct provider access when the application is well controlled, the credential is narrowly scoped, the provider surface changes quickly, or the extra dependency would cost more than it saves. Prefer a workload identity or secret manager when the application genuinely needs the credential and the organization can operate that delivery path.
Consider a purpose-built relay when several applications should use the same application-facing contract, when non-provider deployments should not receive provider credentials, or when a shared operation boundary reduces repeated integration and rotation work.
The right question is not “Can I store this key more safely?” It is “Does this application need the provider credential, or does it need permission to perform one provider operation?”