Signed URLs

Signed URLs provide temporary, secure access to private files stored in S3 or R2. They allow the frontend to display images and download files without exposing storage credentials.

Endpoint

GET /api/files/signed-url?path=avatars/15/photo.jpg

Returns a pre-signed URL that grants temporary access to the specified file:

{
    "url": "https://bucket.s3.amazonaws.com/avatars/15/photo.jpg?X-Amz-Signature=..."
}

Expiration

Signed URLs expire after 1 hour. After expiration, the URL returns a 403 error and a new signed URL must be requested.

Authorization

Access to signed URLs is controlled by ownership rules:

  • Avatars: users can only access their own avatar files
  • Organization logos: only members of the organization can access the logo

Unauthorized requests return a 403 Forbidden response.

Usage in Frontend

The frontend requests signed URLs on demand when displaying images. URLs are cached client-side and refreshed before expiration:

const { data } = useQuery({
    queryKey: ['signed-url', path],
    queryFn: () => api.get('/files/signed-url', { params: { path } }),
    staleTime: 50 * 60 * 1000, // refresh before 1-hour expiry
});