On this page
- The key should live outside normal app data
- The key is usually placed in an authentication header
- HTTPS protects the credential in transit
- The provider sees the credential after TLS terminates
- Authentication and authorization are different
- The provider associates usage with the credential/account
- The key should never be appended to a URL
- Request logging is a major leak risk
- HTTP redirects require special care
- Custom headers can contain secrets too
- The model should never be asked to manage the key
- Provider-side storage policy is separate from key security
- Rotation should not require rewriting chats
- Revocation needs clear behavior
- Memory is a temporary exposure surface
- Backups should exclude credentials by default
- A safe request pipeline
- API-key handling checklist
- Where BYOKchat fits
- Further reading
When an AI client uses an API key, the key is not sent to the model as part of your prompt. It is used by the provider’s API infrastructure to authenticate the request.
A simplified request path looks like this:
The key question is not just “is the key encrypted?” A secure implementation also needs to control where the credential is stored, which host receives it, what gets logged, how it is rotated, and what happens when the provider rejects it.
The key should live outside normal app data
An API key is a bearer credential: possession may be enough to use the associated account within the key’s permissions.
Treat it differently from normal settings.
For a native client, a good data relationship is:
provider connection record
↓
secure credential reference
↓
platform secure storage
Do not store the key inside:
- chat messages;
- analytics events;
- plain JSON preferences;
- Markdown exports;
- crash-report breadcrumbs;
- project files;
- normal application logs.
On Apple platforms, Keychain is generally the appropriate default for long-lived API credentials.
See How to Store API Keys Safely.
The key is usually placed in an authentication header
AI providers commonly authenticate API requests with an HTTP header, although exact header names and schemes are provider-specific.
Conceptually:
POST /model-endpoint HTTP/1.1
Host: api.provider.example
Authorization: Bearer <secret>
Content-Type: application/json
Another provider may use a dedicated header instead of Authorization.
The important properties are:
- the credential is protocol metadata, not prompt content;
- the adapter knows the provider-specific header format;
- the header is attached only to the intended provider origin;
- redirects must not accidentally forward credentials to another host.
HTTPS protects the credential in transit
With a correctly validated HTTPS connection, the HTTP headers and body travel inside TLS encryption between the client and the TLS endpoint.
An observer on ordinary network infrastructure should not see the plaintext API key.
But HTTPS is not magic. Security still depends on:
- correct certificate validation;
- trusted certificate authorities or explicitly managed private certificates;
- no debugging proxy installed as a trusted root without the user’s knowledge;
- no application logging of request headers;
- no accidental downgrade to plaintext HTTP on public networks.
For custom local endpoints, the client may deliberately allow HTTP on a private LAN. That is a different threat model and should be an explicit choice, not the global default.
The provider sees the credential after TLS terminates
TLS protects data between endpoints. It does not hide the credential from the provider you are authenticating to.
At the provider’s edge, the request must be authenticated. The provider can then determine things such as:
which account/key is this?
is the key active?
is this model allowed?
is the account within quota?
what rate-limit bucket applies?
The model itself does not need your API key as text input. Provider infrastructure uses the credential to authorize access before or around model execution.
Authentication and authorization are different
A valid key answers roughly:
this request belongs to account/key X
Authorization asks:
may account/key X perform this operation?
A request can therefore fail even when the key is syntactically valid.
Examples include:
- model not enabled for the account;
- insufficient project permission;
- endpoint not available to the account;
- quota exhausted;
- account restrictions;
- organization policy.
This is why a client should not reduce every 401/403-style failure to “bad key.”
See AI API Errors 401, 403, and 429.
The provider associates usage with the credential/account
Once authenticated, provider-side usage can be attributed to the corresponding account, project, organization, or key according to that provider’s billing model.
Conceptually:
credential identity
↓
request accepted
↓
model usage measured
↓
account quota / billing / analytics updated
A BYOK app can display provider-reported token usage or estimates, but the provider remains authoritative for final account billing.
See Understanding AI API Costs.
The key should never be appended to a URL
Avoid designs like:
https://api.example.com/chat?api_key=secret
URLs are more likely than headers to appear in:
- browser history;
- access logs;
- reverse-proxy logs;
- analytics;
- crash reports;
- copied links;
- referrer data;
- screenshots.
Use the provider’s documented authentication mechanism instead.
Request logging is a major leak risk
A secure network path can still be undermined by application diagnostics.
A careless debug statement such as:
print(request.allHTTPHeaderFields)
can expose credentials to console logs.
A safer logging layer should redact known sensitive fields before serialization:
Authorization: <redacted>
x-api-key: <redacted>
Cookie: <redacted>
Do not rely on developers remembering to redact at every call site. Put redaction into the logging boundary.
HTTP redirects require special care
Imagine a custom endpoint returns:
307 Temporary Redirect
Location: https://other-host.example/path
Blindly forwarding an authorization header can send the key to a host the user never configured.
Credential forwarding rules should be origin-aware.
A conservative client can treat cross-origin redirects as requiring re-evaluation rather than simply cloning the original authenticated request.
This matters especially for user-configurable OpenAI-compatible endpoints.
Custom headers can contain secrets too
Some custom providers require more than one credential-like header.
For example:
Authorization
X-Workspace-Token
X-Gateway-Key
A client should allow protected custom headers to use the same secure-storage and redaction policy as the main API key.
Do not assume only one field named apiKey is sensitive.
The model should never be asked to manage the key
Bad architecture:
system prompt:
"Your API key is sk-..."
or:
tool argument:
{"api_key":"sk-..."}
The model does not need the credential to generate text or decide which tool to call. The host application attaches authentication at the transport boundary.
Keeping credentials outside model-visible data prevents prompt injection or model output from casually exposing them.
Provider-side storage policy is separate from key security
Protecting the API key does not answer what happens to prompts and responses after authentication.
Those are separate concerns:
credential security
≠
provider data retention policy
A provider may have different retention, abuse-monitoring, enterprise, or zero-data-retention arrangements depending on account configuration.
BYOK does not automatically make model inputs local-only.
See How Private Is BYOK AI Chat?.
Rotation should not require rewriting chats
If a user replaces a key, existing conversations should not contain copies of the old secret.
A good connection model makes rotation simple:
connection ID stays stable
credential reference points to new key
future requests use new key
old chat history remains unchanged
This is another reason to separate provider connection metadata from conversation records.
Revocation needs clear behavior
When the user removes a provider connection, the client should:
- delete the locally stored credential;
- stop attaching it to requests;
- cancel pending requests where appropriate;
- keep or remove non-secret connection metadata according to product policy;
- clearly show chats that no longer have a valid connection.
Deleting a local key does not necessarily revoke it at the provider. If the user needs account-level revocation, that happens through the provider’s credential management system.
Memory is a temporary exposure surface
Even if a key lives in Keychain at rest, the app eventually needs to read it into process memory to construct an authenticated request.
You cannot eliminate that entirely.
You can reduce unnecessary exposure:
- load the credential only when needed;
- do not cache extra copies in global state;
- avoid converting secrets repeatedly between string/data representations;
- never include them in debug descriptions;
- clear temporary buffers where practical and supported;
- keep credential-handling APIs narrow.
The goal is minimizing accidental copies, not pretending memory can never contain a credential.
Backups should exclude credentials by default
A backup of chats, projects, and provider configuration can preserve:
provider type
connection name
base URL
model selections
non-secret settings
while omitting:
API keys
auth tokens
protected custom headers
After restore, the app can ask the user to reconnect credentials.
This avoids turning an otherwise portable chat backup into a credential vault.
A safe request pipeline
Security is the result of the whole pipeline, not just one storage API.
API-key handling checklist
Before shipping a BYOK connection, verify that:
- credentials use secure platform storage;
- conversation data stores only a credential reference/connection ID;
- provider adapters attach the correct auth mechanism;
- authentication headers are sent only to intended destinations;
- HTTPS certificate validation is enabled for public endpoints;
- cross-origin redirects do not leak headers;
- logs redact all known secret headers;
- prompts, tool arguments, exports, and analytics never include credentials;
- key rotation does not rewrite chat history;
- deleting a connection removes local credential access;
- backups omit secrets by default;
- provider data-retention policy is documented separately from credential handling.
Where BYOKchat fits
BYOKchat keeps provider credentials isolated from conversation content and stores secrets separately from ordinary app data. Provider connections reference those credentials, while chat history can remain readable, searchable, exportable, and restorable without embedding keys into the conversation model.
That separation is the foundation of a safe BYOK architecture: the key is transport credential state, not user content.