1---
2title: Secrets
3description: Config.Redacted on a Service, Fly.Secret when Fly should own the value, and KMS keys.
4---
5
6Most secrets in a [`Service`](/fly/compute/services) come from your
7`.env`. Yield `Config.Redacted` in the constructor. Alchemy binds the value
8onto the Machine.
9
10Use [`Fly.Secret`](/providers/fly/secret) when the value should be
11shared across Machines and managed in one place by Fly. Use
12[`SecretKey`](/providers/fly/secretkey) for Fly KMS.
13
14## Bind from `.env`
15
16```typescript
17import * as Config from "effect/Config";
18import * as Redacted from "effect/Redacted";
19
20export default class Api extends Fly.Service<Api>()(
21 "Api",
22 { main: import.meta.url, port: 3000 },
23 Effect.gen(function* () {
24 const apiKey = yield* Config.Redacted("API_KEY");
25
26 return {
27 fetch: Effect.gen(function* () {
28 const token = Redacted.value(apiKey);
29 // ...
30 }),
31 };
32 }),
33) {}
34```
35
36`Config.Redacted("API_KEY")` reads `API_KEY` from the env of whoever
37runs the deploy and writes it onto the Machine. At runtime the same
38line resolves from that env var.
39
40The value is `Redacted<string>`. Unwrap with `Redacted.value` only
41where you need the raw string. Do not pass `env: { ... }` on a
42Service. Yield Config.
43
44See [Secrets & Config](/environments/secrets) for combinators and
45stages.
46
47## When Fly should own the secret
48
49`Fly.Secret` is the App vault. Fly injects it as an environment
50variable on every Machine in a [`Fly.App`](/fly/compute/apps). Use it
51when the value is shared and managed in one place, not when only this
52Service reads a deploy-time `.env` key.
53
54```typescript
55import * as Fly from "alchemy/Fly";
56import * as Redacted from "effect/Redacted";
57
58export const Site = Fly.App("Site");
59
60export const ApiToken = Fly.Secret("ApiToken", {
61 app: Site,
62 name: "API_TOKEN",
63 value: Redacted.make("…"),
64});
65```
66
67A `Fly.Secret` targets a `Fly.App`, not a Service's own App. Run the
68Services that read it in that App with `app: Site` — see
69[Group Services in one App](/fly/compute/services#group-services-in-one-app).
70
71`name` is the env-var Machines see. Omit it and Alchemy generates an
72ownership-stamped name. Updating `value` is in place. Changing `app`
73or `name` replaces.
74
75The resolved resource exposes `name`, `digest`, `createdAt`, and
76`updatedAt`. Never the plaintext.
77
78## Get, list, and write
79
80`GetSecret` is bound to one Secret. `ListSecrets` is bound to the
81App. The Service runs in the Secret's App:
82
83```typescript
84export default class Api extends Fly.Service<Api>()(
85 "Api",
86 { app: Site, main: import.meta.url, port: 3000 },
87 Effect.gen(function* () {
88 const get = yield* Fly.GetSecret(ApiToken);
89
90 return {
91 fetch: Effect.gen(function* () {
92 const got = yield* get().pipe(Effect.orDie);
93 return HttpServerResponse.json({ name: got.name });
94 }),
95 };
96 }).pipe(Effect.provide(Fly.GetSecretHttp)),
97) {}
98```
99
100```typescript
101const list = yield* Fly.ListSecrets(Site);
102const { secrets } = yield* list();
103```
104
105From an Action, the org token can list any App in the org. From a
106Machine, deploy tokens are per-App. Mixing Apps on one Machine
107shares one `FLY_API_TOKEN` and is not supported.
108
109Fly only returns plaintext from a Machine in the same App. From
110deploy-time Actions you get metadata (name, digest, timestamps).
111
112Write from an Action with `WriteSecret`:
113
114```typescript
115const Seed = Alchemy.Action(
116 "Seed",
117 Effect.gen(function* () {
118 const secrets = yield* Fly.WriteSecret(ApiToken);
119
120 return Effect.fn(function* () {
121 yield* secrets.update("API_TOKEN", Redacted.make("sk_live_rotated"));
122 });
123 }).pipe(Effect.provide(Fly.WriteSecretHttp)),
124);
125```
126
127Inside a Service, Alchemy mints an App deploy token for the Machine.
128Inside an Action, the ambient `FLY_API_TOKEN` is used instead.
129
130## KMS keys
131
132[`SecretKey`](/providers/fly/secretkey) is an App KMS key, not an
133env secret. Generate a random key or set raw material. Private
134bytes never appear in attributes. Like `Fly.Secret`, it targets a
135`Fly.App`; bind it from a Service that runs in that App (`app: Site`).
136
137```typescript
138export const Signing = Fly.SecretKey("Signing", {
139 app: Site,
140 type: "nacl_sign",
141});
142
143export const Box = Fly.SecretKey("Box", {
144 app: Site,
145 type: "nacl_secretbox",
146});
147```
148
149`type` is Fly's key type (`nacl_sign`, `nacl_box`, `nacl_secretbox`,
150`hs256`, `es256`, `xaes256gcm`, …). Changing `app`, `name`, or
151`type` replaces the key.
152
153## Encrypt, Decrypt, Sign, Verify
154
155One binding per operation. The key is fixed when you bind.
156
157```typescript
158const encrypt = yield* Fly.Encrypt(Box);
159const decrypt = yield* Fly.Decrypt(Box);
160
161const { ciphertext } = yield* encrypt({ plaintext: bytes });
162const { plaintext } = yield* decrypt({ ciphertext });
163const raw = Redacted.value(plaintext);
164```
165
166```typescript
167const sign = yield* Fly.Sign(Signing);
168const verify = yield* Fly.Verify(Signing);
169
170const { signature } = yield* sign({ plaintext: bytes });
171yield* verify({ plaintext: bytes, signature });
172```
173
174Provide the matching `*Http` layer on the Service or Action.
175Generate, set, and delete stay on the `SecretKey` resource.
176
177Decrypt wraps plaintext in `Redacted`. Fly crypto ops need a KMS
178token. Org API tokens are typed `Forbidden`. Encrypt and sign from
179a Service, not a laptop Action.
180
181## Where next
182
183The [tutorial](/fly/tutorial/part-4) reads a `Config.Redacted` secret
184from a Service. [Services](/fly/compute/services) covers
185`Config.Redacted` and grouping Services in one App. [Postgres](/fly/data/postgres),
186[Redis](/fly/data/redis), and [Tigris](/fly/data/tigris) bind
187typed clients (`ConnectPostgres`, `ReadWriteRedis`, `PutObject`)
188that use Fly-owned secrets internally. See the
189[`Secret`](/providers/fly/secret),
190[`GetSecret`](/providers/fly/getsecret),
191[`ListSecrets`](/providers/fly/listsecrets),
192[`SecretKey`](/providers/fly/secretkey),
193[`Encrypt`](/providers/fly/encrypt),
194[`Decrypt`](/providers/fly/decrypt),
195[`Sign`](/providers/fly/sign), and
196[`Verify`](/providers/fly/verify) references.