Security, secrets and secure operations

Security in applications generated with Lino starts in the generated project itself. Lino already registers local secrets, configures sensitive parameters in Aspire, and creates the foundation for JWT, API keys, temporary tokens, and rate limiting policies for APIs.

This page explains why these protections exist and how to keep them as the application evolves. The central idea is that secrets are not born inside the repository and public APIs are not born without usage limits; Lino delivers this pattern to reduce accidental credential leaks and abuse of sensitive endpoints such as login, refresh token, sign-up, and password recovery.

Local project secrets

Lino automatically registers the local secrets required by the generated application. Database, Redis, and RabbitMQ passwords, the JWT key, API keys, and other sensitive values stay in the application's User Secrets instead of being created in versioned files.

lino secret list
lino secret set
lino secret remove
lino secret clear

The commands remain useful for maintenance: use secret list to audit configured keys, secret set to change or register local values, secret remove to delete a key, and secret clear to clear all local secrets for the project.

This flow is integrated with the generated project. When you add resources such as Redis, RabbitMQ, authentication, authorization, SMTP, API keys, or download tokens, Lino keeps sensitive values out of the source code and prepares the application to receive them as environment configuration.

You can also inspect local secrets with .NET and Aspire platform tools, when applicable, such as dotnet user-secrets list or equivalent Aspire resources. The Lino command exists to make this flow more direct within the context of the generated project.

Parameters in Aspire

The Aspire AppHost coordinates resources such as databases, Redis, RabbitMQ, APIs, workers, and web apps. In generated projects, Lino registers sensitive values as Aspire parameters so the application treats these values as external dependencies, not fixed data in the source code.

This includes database, Redis, and RabbitMQ passwords and other values required for local infrastructure. The AppHost passes these parameters to the corresponding resources by using Aspire's secret model, for example with parameters marked as sensitive.

The practical gain is that the secret stops being a detail lost in configuration files and becomes part of the solution execution model. When you run the application through Aspire, services receive the dependencies they need without requiring you to copy passwords into each project manually.

This design also helps deployment. When Aspire publishes artifacts, the need for these parameters still exists: in Docker Compose, for example, placeholders and environment files may appear to be filled in the correct environment; in other targets, the same principle guides how sensitive configuration is passed to the platform.

Rate limiting

Rate limiting reduces abuse, brute force, and improper resource consumption. Lino already configures default policies and applies helpers to generated endpoints so public, authenticated, internal, and sensitive APIs are not created without usage limits.

This matters because an API can authenticate correctly and still suffer volume abuse. Login, refresh token, sign-up, and password recovery are sensitive flows; by default, Lino separates them from common endpoints so they have more conservative limits.

  • Use the generated policies when creating new endpoints.
  • Keep different limits for sensitive endpoints and common endpoints.
  • Combine rate limiting with authentication, validation, and bot protection when necessary.
  • Treat 429 Too Many Requests as the expected response when the limit is exceeded.
PolicyDefault use in LinoHow to apply when evolving
anonymousPublic endpoints without authentication.Use for anonymous APIs that do not create tokens, accounts, or credentials.
authenticated-userAuthenticated traffic partitioned by the current user.Use as the default for common authenticated APIs.
identity-sensitiveLogin, sign-up, refresh token, forgot password, and password change/reset.Use on endpoints that create tokens or codes, or change credentials.
api-keyInternal endpoints protected by API key.Use in service-to-service integrations that follow the API key filter.
download-tokenGeneration of temporary download tokens.Use when authenticated users can issue short-lived links or tokens.

JWT security

When authentication is added, Lino generates the foundation for issuing, reading, and validating JWTs while keeping the signing key out of the source code. The token identifies the user and carries essential claims without turning the JWT into a portable database.

  • Keep the signing key in User Secrets during development and in a secure provider in production.
  • Preserve the issuer, audience, expiration, and algorithm validation configured in the project.
  • Include only the claims required for the authenticated flow.
  • In multi-tenancy, use the user and tenant context that Lino already provides.

The JWT signing key is a critical secret, and Lino already treats this value as sensitive configuration. When creating new environments, pipelines, or deployments, keep the same rule: the key must not appear in commits, Docker images, logs, public files, or real configuration examples.

JWT also does not replace domain authorization. Claims help make decisions, but critical operations still need to consider current state, user status, active permissions, and request context. The generated part provides the foundation; your responsibility when evolving the system is not to create shortcuts that bypass this flow.

API keys and download tokens

Lino treats API keys and temporary tokens as limited-scope credentials. When a flow needs to release temporary access to a file, package, or integration, the generated foundation favors short, specific tokens instead of reusing broad credentials.

  • Use short expiration for links and temporary tokens.
  • Associate the token with the user, tenant, and resource when the flow has that context.
  • Record usage for auditing when access involves sensitive artifacts.
  • Revoke tokens when the resource or permission changes.

APIs protected by key use the authorization and rate limiting model generated by Lino. A key created for integration automation must not become a free pass for administrative calls, and a temporary download token must not replace the authenticated user's permissions.

When creating new download or integration flows, keep the same idea: explicit scope, expiration, useful metadata, and an appropriate rate limiting policy. This keeps temporary access auditable and predictable instead of becoming a loose credential circulating through the system.

Secret providers in production

User Secrets solve local development. In production, keep the same separation by using the platform's secure provider: Azure Key Vault, AWS Secrets Manager, Google Secret Manager, HashiCorp Vault, Kubernetes Secrets, or environment variables protected by the orchestrator.

Lino prepares the application to receive sensitive configuration from outside the code. Moving to production is an environment decision: the names and parameters continue to exist, but the values start coming from the vault, pipeline, or orchestrator used by your infrastructure.

Production also introduces operational practices such as rotation, segregation by environment, permissions per application, and access auditing. User Secrets do not replace these controls; they cover the local experience without putting secrets in the repository.

  • Separate by environment: development, staging, and production must not share credentials.
  • Separate by application: each service should receive only the secrets it needs.
  • Plan rotation: JWT keys, SMTP, API keys, and database passwords need a replacement procedure.
  • Audit access: record who can read or change secrets on the platform.
An unhandled error has occurred. Reload πŸ—™