Authentication
Authentication
Section titled “Authentication”Stowry uses presigned URLs for authentication. This approach allows secure file access without exposing credentials to end users.
How Presigned URLs Work
Section titled “How Presigned URLs Work”- Your server generates a presigned URL using your access key and secret key
- The URL includes a cryptographic signature valid for a limited time
- Users can access the resource using only the URL - no credentials needed
- The signature expires after the specified duration
Authentication Methods
Section titled “Authentication Methods”Stowry supports two signing schemes:
1. Stowry Native Signing (Recommended)
Section titled “1. Stowry Native Signing (Recommended)”Simpler implementation using HMAC-SHA256.
URL Format:
http://localhost:5708/path/to/file?X-Stowry-AccessKey=KEY&X-Stowry-Expires=1705323000&X-Stowry-Signature=abc123...Query Parameters:
| Parameter | Description |
|---|---|
X-Stowry-AccessKey | Your access key ID |
X-Stowry-Expires | Unix timestamp when URL expires |
X-Stowry-Signature | HMAC-SHA256 signature |
2. AWS Signature V4
Section titled “2. AWS Signature V4”Compatible with AWS SDK presigning. Useful if you’re already using AWS SDKs.
URL Format:
http://localhost:5708/bucket/key?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=...&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=...Query Parameters:
| Parameter | Description |
|---|---|
X-Amz-Algorithm | Always AWS4-HMAC-SHA256 |
X-Amz-Credential | Access key and scope |
X-Amz-Date | Request timestamp (ISO 8601) |
X-Amz-Expires | URL validity in seconds (max 604800) |
X-Amz-SignedHeaders | Headers included in signature |
X-Amz-Signature | The signature |
Generating Presigned URLs
Section titled “Generating Presigned URLs”Using stowry-go SDK (Native Signing)
Section titled “Using stowry-go SDK (Native Signing)”import stowry "github.com/sagarc03/stowry-go"
client := stowry.NewClient( "http://localhost:5708", "AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",)
// Generate URLs (expiry in seconds)getURL := client.PresignGet("/photos/vacation.jpg", 900) // 15 minutesputURL := client.PresignPut("/photos/new.jpg", 3600) // 1 hourdeleteURL := client.PresignDelete("/photos/old.jpg", 300) // 5 minutesUsing AWS SDK for Go
Section titled “Using AWS SDK for Go”import ( "context" "time"
"github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/s3")
func createPresignClient() (*s3.PresignClient, error) { cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion("us-east-1"), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( "AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "", )), ) if err != nil { return nil, err }
client := s3.NewFromConfig(cfg, func(o *s3.Options) { o.BaseEndpoint = aws.String("http://localhost:5708") o.UsePathStyle = true })
return s3.NewPresignClient(client), nil}
// Generate presigned GET URLfunc presignGet(client *s3.PresignClient, key string) (string, error) { resp, err := client.PresignGetObject(context.Background(), &s3.GetObjectInput{ Bucket: aws.String("bucket"), Key: aws.String(key), }, s3.WithPresignExpires(15*time.Minute)) if err != nil { return "", err } return resp.URL, nil}
// Generate presigned PUT URLfunc presignPut(client *s3.PresignClient, key string) (string, error) { resp, err := client.PresignPutObject(context.Background(), &s3.PutObjectInput{ Bucket: aws.String("bucket"), Key: aws.String(key), }, s3.WithPresignExpires(15*time.Minute)) if err != nil { return "", err } return resp.URL, nil}Using AWS SDK for Python (Boto3)
Section titled “Using AWS SDK for Python (Boto3)”import boto3from botocore.config import Config
s3_client = boto3.client( 's3', endpoint_url='http://localhost:5708', aws_access_key_id='AKIAIOSFODNN7EXAMPLE', aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', region_name='us-east-1', config=Config(s3={'addressing_style': 'path'}))
# Generate presigned GET URLget_url = s3_client.generate_presigned_url( 'get_object', Params={'Bucket': 'bucket', 'Key': 'photos/vacation.jpg'}, ExpiresIn=900 # 15 minutes)
# Generate presigned PUT URLput_url = s3_client.generate_presigned_url( 'put_object', Params={'Bucket': 'bucket', 'Key': 'photos/new.jpg'}, ExpiresIn=3600 # 1 hour)Using AWS SDK for JavaScript
Section titled “Using AWS SDK for JavaScript”import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const client = new S3Client({ endpoint: 'http://localhost:5708', region: 'us-east-1', credentials: { accessKeyId: 'AKIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', }, forcePathStyle: true,});
// Generate presigned GET URLconst getUrl = await getSignedUrl( client, new GetObjectCommand({ Bucket: 'bucket', Key: 'photos/vacation.jpg' }), { expiresIn: 900 });
// Generate presigned PUT URLconst putUrl = await getSignedUrl( client, new PutObjectCommand({ Bucket: 'bucket', Key: 'photos/new.jpg' }), { expiresIn: 3600 });Using Presigned URLs
Section titled “Using Presigned URLs”Download (GET)
Section titled “Download (GET)”# Using curlcurl -o vacation.jpg "http://localhost:5708/photos/vacation.jpg?X-Stowry-AccessKey=..."
# Or in browser - just visit the URLUpload (PUT)
Section titled “Upload (PUT)”curl -X PUT \ -H "Content-Type: image/jpeg" \ --data-binary @vacation.jpg \ "http://localhost:5708/photos/vacation.jpg?X-Stowry-AccessKey=..."Delete (DELETE)
Section titled “Delete (DELETE)”curl -X DELETE "http://localhost:5708/photos/vacation.jpg?X-Stowry-AccessKey=..."Public Access Mode
Section titled “Public Access Mode”For development or public content, you can disable authentication:
access: public_read: true # Anyone can download public_write: false # Upload still requires authSecurity Best Practices
Section titled “Security Best Practices”-
Keep URLs short-lived - Use the minimum expiration time needed (e.g., 5-15 minutes for downloads)
-
Generate URLs server-side - Never expose your secret key to clients
-
Use HTTPS in production - Presigned URLs should be transmitted over TLS
-
Rotate keys periodically - Update access keys and secret keys regularly
-
Validate paths - Ensure users can only access paths they’re authorized for
-
Log access - Monitor presigned URL usage for suspicious activity
Maximum Expiration
Section titled “Maximum Expiration”- Stowry native signing: No enforced maximum
- AWS Signature V4: Maximum 7 days (604800 seconds)
Troubleshooting
Section titled “Troubleshooting””Signature does not match”
Section titled “”Signature does not match””- Verify access key and secret key are correct
- Check region and service name match configuration
- Ensure URL hasn’t been modified after signing
- Verify system clock is synchronized (within 5 minutes)
“Request has expired”
Section titled ““Request has expired””- The presigned URL has passed its expiration time
- Generate a new URL with longer expiration if needed
”Missing authentication”
Section titled “”Missing authentication””- URL is missing required signature parameters
- Ensure you’re using a properly signed URL