# File.SignedUrl

> Mints a temporary, signed URL that lets an authorized browser fetch a PRIVATE app file — one stored outside `public/` — without carrying a login token. `File.Url` serves only public files; `File.SignedUrl` is how a private report, invoice, or per-user image reaches the browser. The link expires on its own after a few minutes.

<!-- id: storage-file-signed-url · area: storage · stability: preview · html: https://osysharp.com/reference/storage/file-signed-url/ -->

## Summary        {#summary}
**`File.SignedUrl(path)`** returns a URL a browser can use to fetch a **private** app file — a file stored under any
path *other* than `public/`. The URL carries a short-lived, cryptographically signed token, so it works for anyone who
holds the link until it expires, and 404s otherwise. Use it for a per-user report, an invoice PDF, or a private image:

```osy syntax
string url = File.SignedUrl("reports/" + user.Id + "/q3.pdf");
```

Like the rest of the `File.*` surface it is gated on **`using Osysharp.Storage;`**.

## Signature      {#signature}
```osy syntax
using Osysharp.Storage;

string File.SignedUrl(string path)
```

## Description    {#description}
The app-file serving route treats `public/` and everything else very differently. A file under `public/` is served to
**anyone**, anonymously, and its URL is just [File.Url](https://osysharp.com/reference/storage/file-url/). A file under any other path is **private**: the
serving route refuses it outright — until the request carries a valid signed token. `File.SignedUrl` mints that token.

### Can I put it straight in a render argument?        {#server-side}
This is the key difference from [File.Url](https://osysharp.com/reference/storage/file-url/). `File.Url` is pure string formatting, so it can sit directly in a
render argument (`Image(src: File.Url(...))`) and be built by the browser. `File.SignedUrl` **signs with your app's
key**, which the browser never holds — so it runs on the server, inside a function or action. Call it where you have
the path in hand (an action that prepares a download, a function that returns a link) and hand the result to the UI.

### Who can use the link, and for how long?        {#temporary-capability}
A signed URL is a **bearer link**: whoever holds it can fetch that one file until it expires. That is exactly what lets
a browser `<img>` or a download load without a login header. Two properties keep it safe:

- **It expires.** The link is valid for a short window (currently 15 minutes), then stops working. Mint it when the
  page or download is requested, not far in advance.
- **It unlocks exactly one file, for one app.** The path and your application are sealed inside the token, so a link
  minted for `reports/a.pdf` cannot be edited to fetch `reports/b.pdf`, and a link from one app is meaningless on
  another. A tampered or expired link simply 404s — a private file's existence is never revealed to someone without a
  valid link.

You never see, choose, or store a key — the platform mints, protects, and rotates it, exactly as for
[Crypto.Encrypt and Crypto.Decrypt](https://osysharp.com/reference/function/crypto-encrypt/).

`File.SignedUrl` is signing, not a storage read: it does **not** check that the file exists (a missing file 404s when
the browser follows the link), and it is not available inside a query.

## Examples       {#examples}

An action returns a private, expiring download link for the caller's own report:

```osy title="a private, expiring download link" test app=storage-file-signed-url
using Osysharp.Storage;

[Principal] entity User { [MaxLength(200)] string Email; }

// The report was written earlier under a NON-public path, so it is not servable anonymously.
string ReportDownloadUrl(User user) {
  return File.SignedUrl("reports/" + user.Id + "/q3.pdf");
}
```

Writing a private file, then handing back a link to it:

```osy title="write a private file, then hand back a link" test app=storage-file-signed-url
using Osysharp.Storage;

string SaveAndLinkInvoice(string invoiceId, byte[] pdf) {
  var path = "invoices/" + invoiceId + ".pdf";   // NOT under public/ — private by default
  File.WriteAllBytes(path, pdf);
  return File.SignedUrl(path);                    // a temporary link the browser can open
}
```

## See also       {#see-also}
- [File.Url](https://osysharp.com/reference/storage/file-url/) — the public counterpart: a plain, permanent URL for a `public/` file
- [Crypto.Encrypt and Crypto.Decrypt](https://osysharp.com/reference/function/crypto-encrypt/) — the same "the platform owns your key" model, for encrypting stored values
