# declaring secrets (app.Secrets)

> `app.Secrets` declares the named secrets your app uses — API keys, tokens, client secrets. Each is `new Secret("Name")`, optionally `{ UserScoped = true }` for a per-user secret rather than one app-wide value. Everything else references a secret by its `Secret.Name` handle — a model client's `ApiKey`, an OAuth client's `ClientSecret`. A secret's VALUE is never in source, only its name; the value lives in the secret store.

<!-- id: config-secrets · area: config · stability: stable · html: https://osysharp.com/reference/config/secrets/ -->

## Summary        {#summary}
`app.Secrets` declares the named secrets your application **consumes** — a provider's API key, an access token, an
OAuth client secret. You declare a secret's **name** here; you never write its **value** in source.

⚠ **Not the API key of an API your app PUBLISHES.** That is a different direction and a different mechanism: a
published `app.Apis` route gated `Auth = new ApiAuth { ApiKey = true }` is authenticated by a **per-user** key kept on
the app's `[Principal]` row, and nothing in `ApiAuth` names a `Secret`. See [publishing a REST API (app.Apis)](https://osysharp.com/reference/api/rest/).

Each secret is `new Secret("Name")`, and optionally `{ UserScoped = true }` to make it a per-user secret rather than a
single app-wide value. Every other config slot that needs a secret refers to it by its `Secret.Name` handle rather than
by an inline string.

```osy syntax
app.Secrets = [
  new Secret("OpenAI"),
  new Secret("PersonalToken") { UserScoped = true },
];
```

## Signature      {#signature}
```osy
app.Secrets = [                              // one entry per named secret
  new Secret("Anthropic"),                            // app-wide: one value for the whole app
  new Secret("CalendarToken") { UserScoped = true },  // per-user: each user supplies their own value
];
```

`app.Secrets` is a list — an app may declare as many named secrets as it needs. Everywhere else refers to one by its
`Secret.Name` handle and never by a literal: on a model client, on the embedder's `ApiKey`, on an OAuth client's
`ClientSecret`, in a function body. The worked form is under Examples below.

## Description    {#description}
**Declaring one is what brings the storage in.** `app.Secrets = [ … ]` is a *declaration trigger*: writing it opts
the app into the `Osysharp.Secrets` capability, which is where the values are kept. There is no `use` line to write
and never was — the declaration IS the request, so an app that declares no secret carries no secret table at all.
(Before 2026-09 every app carried it regardless; of 53 projects measured, 7 declared a secret and 46 did not.)

Each entry is a `new Secret("Name")`, where the name is a **string literal**. That name is the only thing that lives in
source. The secret's actual value — the key, token, or password — is never written in your app; it lives in the secret
store and is supplied separately. On your own machine you supply it with `osy secret set`
([Giving a secret its value](https://osysharp.com/reference/local/giving-a-secret-its-value/)); a deployed app's values are supplied by whoever operates its platform.

- **`new Secret("Name")`** — declares an **app-wide** secret. There is one value, shared by the whole application, used
  for every request regardless of who makes it (for example, one server-side API key for a provider).
- **`{ UserScoped = true }`** — makes the secret **per-user** instead. Every user of the app supplies their own value,
  and the secret resolves to the value belonging to the current user. Use this when the credential belongs to the
  person, not the app (for example, a user's personal access token).

Once declared, a secret is referenced everywhere else by its **`Secret.Name` handle** — not by re-typing the name as a
string and never by the value. A model client's `ApiKey`, an OAuth client's `ClientSecret`, and a REST API's key all
take a `Secret.Name` handle. The handle is how the platform links a config slot to the stored value at runtime while
keeping the value itself out of your source.

## Examples       {#examples}
Declare an app-wide secret and reference it from the embedder's `ApiKey`:

```osy title="basic" test app=config-secrets-example
app.Secrets = [ new Secret("OpenAI") ];

// The handle is read where the thing that needs it is declared; the value never appears in source.
app.Embedding = new EmbeddingConfig {
  Provider   = EmbeddingProvider.OpenAI,
  Model      = "text-embedding-3-small",
  ApiKey     = Secret.OpenAI,
  Dimensions = 1536,
};
```

A per-user secret — each user supplies their own value:

```osy title="user-scoped" test app=config-secrets-userscoped
app.Secrets = [ new Secret("PersonalToken") { UserScoped = true } ];
```

## See also       {#see-also}
- [reading a secret's value (Secret.Name)](https://osysharp.com/reference/function/secret-read/) — reading a declared secret's VALUE inside a function body
- [Giving a secret its value](https://osysharp.com/reference/local/giving-a-secret-its-value/) — how a declared secret gets its value on your machine
- [OAuth clients (app.OAuthClients)](https://osysharp.com/reference/config/oauth-clients/) — an OAuth client's `ClientSecret` is a `Secret.Name` handle
- [embedding provider (app.Embedding)](https://osysharp.com/reference/config/embedding/) — `app.Embedding`, whose `ApiKey` is a `Secret.Name` handle
- [The Llm kit — call a model, and know what each call cost](https://osysharp.com/reference/agent/llm-calls/) — a model's client takes one the same way: `new AnthropicClient { ApiKey = Secret.Anthropic }`
- [publishing a REST API (app.Apis)](https://osysharp.com/reference/api/rest/) — `app.Apis`. ⚠ A REST API's key is NOT one of these: `ApiAuth` names no `Secret`, and a
  published API's key is a per-user credential kept on the `[Principal]` row
