Anvil.Auth.SignedURL (Anvil v0.1.1)

View Source

Time-limited signed URLs for secure asset access.

Generates cryptographically signed URLs with expiration timestamps for accessing sensitive resources (samples, artifacts, etc).

URLs contain:

  • Resource identifier
  • Expiration timestamp
  • HMAC signature (prevents tampering)

Example

# Generate signed URL (expires in 1 hour)
{:ok, url} = SignedURL.generate("sample-123", secret, expires_in: 3600)

# Verify URL before serving asset
case SignedURL.verify(url, secret) do
  {:ok, resource_id} -> serve_asset(resource_id)
  {:error, :expired} -> {:error, :url_expired}
  {:error, :invalid_signature} -> {:error, :unauthorized}
end

Summary

Functions

Checks if a signed URL has expired.

Extracts the resource ID from a signed URL without verification.

Generates a signed URL for a resource.

Returns time remaining before URL expires (in seconds).

Verifies a signed URL and returns the resource ID if valid.

Types

error_reason()

@type error_reason() :: :malformed_url | :invalid_signature | :expired

opts()

@type opts() :: keyword()

resource_id()

@type resource_id() :: String.t()

secret()

@type secret() :: String.t()

url()

@type url() :: String.t()

Functions

expired?(url)

@spec expired?(url()) :: boolean()

Checks if a signed URL has expired.

Examples

iex> {:ok, url} = SignedURL.generate("sample-123", "secret", expires_in: 3600)
iex> SignedURL.expired?(url)
false

extract_resource_id(url)

@spec extract_resource_id(url()) :: {:ok, resource_id()} | {:error, :malformed_url}

Extracts the resource ID from a signed URL without verification.

Examples

iex> {:ok, url} = SignedURL.generate("sample-123", "secret")
iex> SignedURL.extract_resource_id(url)
{:ok, "sample-123"}

generate(resource_id, secret, opts \\ [])

@spec generate(resource_id(), secret(), opts()) :: {:ok, url()}

Generates a signed URL for a resource.

Options

  • :expires_in - Expiration time in seconds (default: 3600 / 1 hour)
  • :tenant_id - Include tenant ID in signature for multi-tenant isolation
  • :base_url - Base URL for the resource (default: "http://localhost/assets")

Examples

iex> {:ok, url} = SignedURL.generate("sample-123", "secret-key")
iex> String.contains?(url, "sample-123")
true

iex> {:ok, url} = SignedURL.generate("sample-123", "secret", expires_in: 7200)
iex> String.contains?(url, "signature=")
true

time_remaining(url)

@spec time_remaining(url()) :: {:ok, integer()} | {:error, :malformed_url}

Returns time remaining before URL expires (in seconds).

Returns negative value if already expired.

Examples

iex> {:ok, url} = SignedURL.generate("sample-123", "secret", expires_in: 3600)
iex> {:ok, remaining} = SignedURL.time_remaining(url)
iex> remaining > 3595
true

verify(url, secret, opts \\ [])

@spec verify(url(), secret(), opts()) ::
  {:ok, resource_id()} | {:error, error_reason()}

Verifies a signed URL and returns the resource ID if valid.

Options

  • :tenant_id - Expected tenant ID (must match signature)

Examples

iex> {:ok, url} = SignedURL.generate("sample-123", "secret")
iex> SignedURL.verify(url, "secret")
{:ok, "sample-123"}

iex> SignedURL.verify("invalid-url", "secret")
{:error, :malformed_url}