Claude Skills Guide

Claude Code Supabase Storage Signed URL Workflow Guide

Supabase Storage provides a powerful, secure way to handle file uploads and downloads in your applications. When combined with Claude Code, you can build intelligent file management systems that understand context, validate content, and automate complex workflows. This guide walks you through creating signed URL workflows that keep your files secure while enabling powerful AI-driven interactions.

Understanding Signed URLs in Supabase Storage

Supabase Storage uses signed URLs to provide temporary, secure access to private files. Unlike public buckets where anyone with the URL can access files, signed URLs include cryptographic tokens that expire after a specified time. This approach is essential for:

When you create a signed URL, Supabase generates a unique token embedded in the URL that validates the requester’s identity and permissions. The URL typically expires in 60 seconds to 3,600 seconds (1 hour), giving you fine-grained control over access duration.

Setting Up Your Supabase Client

Before creating signed URL workflows, you’ll need to configure your Supabase client. Install the Supabase JavaScript client and set up authentication:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.SUPABASE_URL;
const supabaseKey = process.env.SUPABASE_ANON_KEY;

const supabase = createClient(supabaseUrl, supabaseKey);

For Claude Code skills, you might prefer using the Supabase CLI or API directly within your skill definitions. Here’s how to structure a skill for file operations:

---
name: supabase-storage-manager
description: Manage Supabase Storage with signed URLs
---

You are a storage manager that helps users upload, download, and manage files in Supabase Storage using signed URLs.

Creating Signed URLs for Downloads

The most common use case for signed URLs is enabling temporary access to private files. Here’s a practical function to generate download signed URLs:

async function getSignedDownloadUrl(bucketName, filePath, expiresIn = 3600) {
  const { data, error } = await supabase
    .storage
    .from(bucketName)
    .createSignedUrl(filePath, expiresIn);
  
  if (error) {
    throw new Error(`Failed to create signed URL: ${error.message}`);
  }
  
  return data.signedUrl;
}

This function takes three parameters: the bucket name, the file path within the bucket, and the expiration time in seconds. The returned signed URL can be used directly in your application or passed to Claude Code for further processing.

For Claude Code skills, you can wrap this in a bash call to the Supabase CLI:

supabase storage sign my-bucket/documents/report.pdf --expires-in 3600

Building Upload Workflows with Signed URLs

Upload workflows require a two-step process: first, generate a signed URL that allows uploading to a specific path, then use that URL to perform the actual upload. This separation keeps your service role keys secure while enabling direct uploads from clients.

async function getSignedUploadUrl(bucketName, filePath, contentType) {
  const { data, error } = await supabase
    .storage
    .from(bucketName)
    .createSignedUploadUrl(filePath);
  
  if (error) {
    throw new Error(`Failed to create upload URL: ${error.message}`);
  }
  
  return {
    signedUrl: data.signedUrl,
    path: data.path
  };
}

The signed upload URL allows PUT requests to the specific file path, preventing users from uploading to arbitrary locations in your bucket.

Integrating with Claude Code Skills

Claude Code can orchestrate complex file workflows by combining signed URLs with its understanding capabilities. Here’s a skill that processes uploaded documents:

---
name: document-processor
description: Process uploaded documents with AI analysis
---

You help users process documents by downloading them via signed URLs, analyzing content, and storing results.

When Claude Code needs to download a file, it can call your signed URL endpoint:

# Pseudocode for Claude Code skill action
DOWNLOAD_URL=$(getSignedDownloadUrl "user-documents" "uploads/$FILE_ID")
curl -o "$LOCAL_PATH" "$DOWNLOAD_URL"

This enables Claude Code to:

Handling Edge Cases and Errors

Robust signed URL workflows need proper error handling. Common issues include:

Expired URLs: If a signed URL expires before use, regenerate a new one and retry the operation.

Invalid Paths: Validate file paths to prevent path traversal attacks. Always sanitize user input:

function validateFilePath(filePath) {
  const normalized = filePath.replace(/^\/+|\/+$/g, '');
  if (normalized.includes('..')) {
    throw new Error('Invalid path: parent directory references not allowed');
  }
  return normalized;
}

Bucket Permissions: Ensure your Supabase RLS policies allow the appropriate operations. Test signed URLs with different user contexts to verify access control.

Security Best Practices

When implementing signed URL workflows, follow these security guidelines:

  1. Use Short Expiration Times: For sensitive operations, use URLs that expire in 60-300 seconds rather than the maximum 1 hour.

  2. Validate Content Types: Specify content-type restrictions in your upload signed URLs to prevent malicious file uploads.

  3. Implement Rate Limiting: Prevent abuse by limiting signed URL requests per user or IP address.

  4. Audit Access Logs: Track signed URL generation and usage to identify suspicious patterns.

  5. Rotate Service Keys Regularly: If using service role keys for signed URL generation, rotate them periodically.

Complete Workflow Example

Here’s a complete example combining all elements into a practical workflow:

class SupabaseStorageWorkflow {
  constructor(supabaseClient) {
    this.client = supabaseClient;
  }
  
  async uploadAndProcess(file, userId) {
    const filePath = `uploads/${userId}/${Date.now()}-${file.name}`;
    
    const { signedUrl } = await this.getSignedUploadUrl('documents', filePath);
    
    await this.uploadFile(signedUrl, file);
    
    const downloadUrl = await this.getSignedDownloadUrl('documents', filePath, 300);
    
    return {
      path: filePath,
      accessUrl: downloadUrl,
      expiresIn: 300
    };
  }
  
  async getSignedUploadUrl(bucket, path) {
    const { data, error } = await this.client.storage
      .from(bucket)
      .createSignedUploadUrl(path);
    
    if (error) throw error;
    return data;
  }
  
  async getSignedDownloadUrl(bucket, path, expiresIn = 3600) {
    const { data, error } = await this.client.storage
      .from(bucket)
      .createSignedUrl(path, expiresIn);
    
    if (error) throw error;
    return data.signedUrl;
  }
  
  async uploadFile(signedUrl, file) {
    const response = await fetch(signedUrl, {
      method: 'PUT',
      body: file,
      headers: { 'Content-Type': file.type }
    });
    
    if (!response.ok) {
      throw new Error(`Upload failed: ${response.statusText}`);
    }
  }
}

Conclusion

Signed URLs provide the foundation for secure, flexible file handling in Supabase-powered applications. By integrating these workflows with Claude Code, you can build intelligent systems that understand context, automate document processing, and create dynamic file management experiences. Start with the basics—creating download and upload URLs—then layer in more complex workflows as your needs grow.

The key is maintaining security through short expirations and proper validation while using Claude Code’s AI capabilities to add intelligence to your file operations.

Built by theluckystrike — More at zovo.one