Handling Secrets#
Overview#
Two data structures are available to assist in handling secrets in web services:
SecretString
and SecretBytes
. These are
containers for holding sensitive data within your application.
Secret Parameters#
The following example demonstrates how to use SecretString
to accept a secret value as a parameter in a GET request:
from __future__ import annotations
from dataclasses import dataclass
from secrets import compare_digest
from typing_extensions import Annotated
from litestar import get
from litestar.datastructures.secret_values import SecretString
from litestar.exceptions import NotAuthorizedException
from litestar.params import Parameter
SECRET_VALUE = "super-secret" # An example secret value - this should be stored securely in production.
@dataclass
class Sensitive:
value: str
@get(sync_to_thread=False)
def get_handler(secret: Annotated[SecretString, Parameter(header="x-secret")]) -> Sensitive:
if not compare_digest(secret.get_secret(), SECRET_VALUE):
raise NotAuthorizedException
return Sensitive(value="sensitive data")
from __future__ import annotations
from dataclasses import dataclass
from secrets import compare_digest
from typing import Annotated
from litestar import get
from litestar.datastructures.secret_values import SecretString
from litestar.exceptions import NotAuthorizedException
from litestar.params import Parameter
SECRET_VALUE = "super-secret" # An example secret value - this should be stored securely in production.
@dataclass
class Sensitive:
value: str
@get(sync_to_thread=False)
def get_handler(secret: Annotated[SecretString, Parameter(header="x-secret")]) -> Sensitive:
if not compare_digest(secret.get_secret(), SECRET_VALUE):
raise NotAuthorizedException
return Sensitive(value="sensitive data")
Note
When storing and comparing secrets, use secure practices to prevent unauthorized access. For example, use
environment variables, secret management services, or encrypted databases to store secrets securely. When comparing
secrets, use secrets.compare_digest()
or similar to mitigate the risk of timing attacks.
Note
The headers
attribute of the ASGIConnection
object stores the headers exactly as they are parsed from the ASGI message. Care should be taken to ensure that
these headers are not logged or otherwise exposed in a way that could compromise the security of the application.
Secret Body#
This example demonstrates use of a data structure with a SecretString
field to accept a secret
within the HTTP body of a request:
from dataclasses import dataclass
from litestar import post
from litestar.datastructures.secret_values import SecretString
@dataclass
class Sensitive:
value: SecretString
@post(sync_to_thread=False)
def post_handler(data: Sensitive) -> Sensitive:
return data
Security Considerations#
While SecretString
and SecretBytes
can help in securely transferring secret data through the framework,
it’s vital to adopt secure practices for storing and comparing secrets within your application. Here are a few
guidelines:
Store secrets securely, using environment variables, secret management services, or encrypted databases.
Always use constant time comparison functions such as
secrets.compare_digest()
for comparing secret values to mitigate the risk of timing attacks.Implement access controls and logging to monitor and restrict who can access sensitive information.