Skip to main content
View as Markdown

URL signées

Les URL signées accordent un accès temporaire et restreint aux fichiers privés sans exposer les identifiants de stockage ni rendre le fichier publiquement permanent. Une URL signée intègre un jeton HMAC-SHA256 (signé avec AUTH_SECRET) qui encode le chemin, l'opération et l'expiration. Falsifier n'importe quelle partie invalide le jeton.

Les URL signées fonctionnent sur les trois backends de stockage. Pour les backends S3, Sovrium délègue à la présignature S3 native ; pour les backends local et bytea, il génère et valide les signatures en interne — aucun SDK AWS requis à la couche application.

Accès public vs privé

Par défaut, les fichiers sont privés et requièrent soit une authentification soit une URL signée. Les opérateurs peuvent découper des préfixes de chemin toujours publics.

Variable Par défaut Objectif
STORAGE_DEFAULT_ACCESS private Niveau d'accès par défaut pour les nouveaux fichiers (private ou public).
STORAGE_PUBLIC_PATHS (aucun) Préfixes de chemin séparés par des virgules servis sans authentification ni URL signées.
STORAGE_DEFAULT_ACCESS=private
STORAGE_PUBLIC_PATHS=assets/,avatars/,logos/
Comportement Résultat
Fichier sous un préfixe STORAGE_PUBLIC_PATHS Servi sans authentification ni URL signée.
Fichier hors des chemins publics, pas d'URL signée valide 403 Forbidden.
STORAGE_DEFAULT_ACCESS=public Tous les fichiers accessibles sans URL signées.

La configuration des chemins publics est validée au démarrage — pas de caractères génériques en fin, pas de préfixes qui se chevauchent. Un bucket marqué public: true dans le schéma est l'équivalent par bucket (voir Présentation des buckets).

URL signées de téléchargement

Demandez une URL de téléchargement limitée dans le temps pour un fichier privé.

POST /api/buckets/{bucket}/sign
Content-Type: application/json
Authorization: Bearer <token>

{
  "path": "documents/contract.pdf",
  "expiresIn": 3600,
  "operation": "download"
}
{
  "signedUrl": "https://app.example.com/api/buckets/documents/files/documents/contract.pdf?token=eyJhbGciOiJIUzI1NiJ9...",
  "path": "documents/contract.pdf",
  "expiresAt": "2026-04-05T11:00:00Z"
}
Paramètre Type Requis Par défaut Description
path string Oui Chemin du fichier relatif à la racine de stockage.
expiresIn integer Non 3600 Expiration en secondes. Plage : 60 à 604800 (7 jours).
operation string Non download download ou upload.
Comportement Résultat
Chemin valide URL signée plus horodatage expiresAt.
Accès à l'URL avant expiration Fichier servi sans authentification supplémentaire.
Accès après expiration 403 Forbidden.
expiresIn < 60 ou > 604800 400 Bad Request.
Chemin inexistant 404 Not Found.
Jeton falsifié 403 Forbidden.

URL signées de téléversement

Émettez un jeton d'écriture pour qu'un navigateur puisse téléverser directement vers le stockage sans faire transiter les octets par le serveur d'application.

POST /api/buckets/{bucket}/sign
Content-Type: application/json
Authorization: Bearer <token>

{
  "path": "uploads/user-123/profile-photo.jpg",
  "expiresIn": 600,
  "operation": "upload",
  "contentType": "image/jpeg",
  "maxSize": 5242880
}
{
  "signedUrl": "https://app.example.com/api/buckets/uploads/files/uploads/user-123/profile-photo.jpg?token=eyJhbGciOiJIUzI1NiJ9...",
  "path": "uploads/user-123/profile-photo.jpg",
  "expiresAt": "2026-04-05T10:10:00Z",
  "method": "PUT",
  "headers": { "Content-Type": "image/jpeg" }
}
Paramètre Type Requis Par défaut Description
contentType string Non Type MIME requis, appliqué côté serveur sur le PUT.
maxSize integer Non 10485760 (10 Mo) Taille maximale de téléversement en octets.
Comportement Résultat
Téléversement via l'URL PUT Fichier stocké au chemin spécifié.
Téléversement après expiration 403 Forbidden.
Mauvais type MIME (quand contentType est défini) 400 Bad Request.
Dépasse maxSize 413 Payload Too Large.
Réutiliser un jeton de téléversement pour télécharger Rejeté — l'opération est encodée dans le jeton.

Signature par lot

Générez des URL signées pour jusqu'à 100 fichiers en une seule requête — utile pour afficher une page pleine d'images privées.

POST /api/buckets/{bucket}/sign/batch
Content-Type: application/json
Authorization: Bearer <token>

{
  "files": [
    { "path": "photos/photo-1.jpg", "expiresIn": 3600 },
    { "path": "photos/photo-2.jpg", "expiresIn": 3600 },
    { "path": "documents/report.pdf", "expiresIn": 7200 }
  ]
}

Chaque fichier peut porter son propre expiresIn. Les fichiers inexistants sont renvoyés avec une entrée error: "not_found" (succès partiel plutôt que d'échouer tout le lot). Demander plus de 100 fichiers renvoie 400 Bad Request.

Récapitulatif des points de terminaison

Méthode Point de terminaison Auth
POST /api/buckets/{bucket}/sign Requise (session).
POST /api/buckets/{bucket}/sign/batch Requise (session).
GET /api/buckets/{bucket}/files/{path}?token=... Aucune — le jeton est l'authentification.
PUT /api/buckets/{bucket}/files/{path}?token=... Aucune — le jeton est l'authentification.

Appeler l'un ou l'autre des points de terminaison sign sans session valide renvoie 401.

Contrôle d'accès

Qui peut signer est régi par deux couches indépendantes, toutes deux utilisant le format partagé PermissionValueSchema (all | authenticated | liste de rôles).

Permissions par bucket

Définissez sign et signUpload sur le bucket.

buckets:
  - name: documents
    permissions:
      sign: authenticated
      signUpload: [admin, editor]
      download: authenticated
      delete: [admin]

  - name: public-assets
    public: true
    permissions:
      sign: all
      signUpload: [admin]
      download: all
Comportement Résultat
L'appelant correspond à permissions.sign Peut générer des URL signées de téléchargement.
L'appelant correspond à permissions.signUpload Peut générer des URL signées de téléversement.
L'appelant ne correspond pas 403 Forbidden.
Le bucket n'a pas de bloc permissions Seul le rôle admin peut signer (par défaut).

Permissions de stockage par rôle

Les rôles peuvent accorder ou révoquer indépendamment la signature via storage.sign / storage.signUpload.

auth:
  roles:
    - name: member
      permissions:
        storage:
          sign: true
          signUpload: false
    - name: viewer
      permissions:
        storage:
          sign: false
          signUpload: false

Admin dispose des pleins droits de signature par défaut. Lorsqu'aucune permission de stockage n'est définie nulle part, la signature est par défaut réservée à admin.

Intégration au champ de pièce jointe

Lorsqu'un champ de pièce jointe de table pointe vers un fichier privé, la réponse de l'API d'enregistrement intègre automatiquement une URL de téléchargement signée (expiration par défaut d'1 heure) :

{
  "id": 1,
  "name": "Q1 Report",
  "attachment": {
    "path": "documents/q1-report.pdf",
    "filename": "q1-report.pdf",
    "size": 245760,
    "mimeType": "application/pdf",
    "signedUrl": "https://app.example.com/api/buckets/documents/files/documents/q1-report.pdf?token=...",
    "signedUrlExpiresAt": "2026-04-05T11:00:00Z"
  }
}

Les fichiers publics incluent une URL directe sans jeton. Les pièces jointes d'image peuvent porter des paramètres de transformation à l'intérieur de l'URL signée.

Pages associées