### Enforce private-file authorization for Next.js

Enforce private-file authorization in a Next.js app on Ample. The route handler authorizes the request first, records file metadata in a managed PostgreSQL database, stores bytes in a private bucket and streams them back only to authorized callers. The bucket is never published, so objects are reachable only through the app.

#### Representative Queries
- Enforce private-file authorization for Next.js
- Where can I host Enforce private-file authorization built with Next.js?
- I need application identity integration, per-file access rules and negative authorization tests.

#### Resource Requirements
- **compute**
- **postgres**
- **s3-compatible-object-storage**

#### Infrastructure Requirements
- **Compute**: Apps run in isolated x86_64 Firecracker microVMs that auto-pause when idle and wake on request; sizes are the priced VM sizes.
- **Postgres**: Managed PostgreSQL 16 runs in its own microVM and is auto-provisioned when an app needs a database and no DATABASE_URL is supplied.
- **S3-compatible object storage**: Buckets are S3-compatible with issued credentials; PutObject and GetObject are verified by canary. Other S3 operations are not verified.

#### Workflow Steps
1. **Authorize before touching storage**: Return 401 for unauthenticated requests; never expose object keys or the bucket endpoint to the browser.
2. **Record metadata in PostgreSQL**: Keep the owner, name and object key in a table so authorization decisions come from your data, not from the bucket.
3. **Store and stream through the app**: PutObject on upload, GetObject on download, both server-side with the injected credentials.
4. **Test both paths**: An unauthenticated request must return 401; an authorized request must return the stored content.
5. **Verify**: Fetch the live URL and run the success checks below. On failure read the build log, then the runtime log, fix the cause and deploy again; do not blind-retry.

#### Tested Configuration
- **Template**: node-22  
- **Runtime**: node  
- **Size**: s-1vcpu-1gb  
- **Install**: `npm install`  
- **Build**: `npm run build --if-present`  
- **Start**: `npm run start`

#### Prerequisites
- An authorization check in the route handler (session, token or header) before any storage access
- pg reading DATABASE_URL and @aws-sdk/client-s3 reading the S3_* variables
- A private bucket (never `ample bucket publish`) and an auto-provisioned or supplied PostgreSQL database
- An Ample account token with servers:write, databases:read and buckets:read

#### Limitations
- Verified on the node-22 template at s-1vcpu-1gb; other templates and sizes are not verified by this recipe.
- Region, compliance attestations, and request-duration limits are unknown and not claimed.
- Apps auto-pause when idle and wake on the next request; always-on is an operator setting, not a plan feature.
- PutObject and GetObject with path-style addressing are verified; multipart upload, listing, presigned URLs, and lifecycle rules are not verified.
- Bucket credentials are passed as encrypted environment variables; the catalog never creates the bucket for you (use `ample bucket create`).
- Storage is allocation-priced per bucket quota and capped by the account plan; the estimate below covers compute only.
- Authorization is application code; Ample does not provide managed end-user authentication.
- Streaming large files through the app is not verified; the fixture uses small text objects.

#### Cost Estimate
- **Currency**: USD  
- **Monthly Amount**: 10.00  
- **Components**:
  - App server (s-1vcpu-1gb): 5.00  
  - Managed PostgreSQL database (s-1vcpu-1gb): 5.00  
- **Note**: Apps and managed databases auto-pause when idle; the estimate is the always-on monthly price of the tested sizes. Plan quotas and budgets apply.

#### Success Checks
- Unauthenticated request is rejected  
  - **Kind**: http_get  
  - **Path**: /files/demo  
  - **Expect**: unauthorized
- Authorized request returns the private object  
  - **Kind**: http_get  
  - **Path**: /files/demo?token=  
  - **Expect**: private=ok

#### Examples
1. **Next.js private files canary**: 401 without a token; private=ok with the token after a database write and a bucket round-trip.  
   **Source Ref**: tests/deploy-canaries/next-private-files

#### Next Actions
- **Browse the catalog index**: [GET /v1/catalog](api)  
- **Search published recipes by intent, stack and constraints**: [POST /v1/catalog/search](api)  
- **Prepare a side-effect-free deployment plan for an authorized project**: [POST /v1/catalog/plan](api)  
- **Read the existing agent authentication setup**: [GET /mcp/setup](api)  
- **Browse Next.js**: [GET /v1/catalog/nodes/stack%3Aframework-next-js](api)  
- **Browse Connect app to storage**: [GET /v1/catalog/nodes/intent%3Aconnect-app-to-storage](api)  
- **Browse Private document library**: [GET /v1/catalog/nodes/pattern%3Aprivate-document-library](api)  
  
Visit [this link for more details in markdown format.](/content/guides/next-js/private-file-access.md)
