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
- Présentation des buckets — buckets, backends et le commutateur
public. - Opérations sur les fichiers — téléversement, téléchargement et suppression directs.
- Transformations d'image — combiner les transformations avec les URL signées.
- Champs de pièce jointe — auto-signature dans les réponses d'enregistrement.
- Variables d'environnement — configuration des chemins publics et du niveau d'accès.