---
title: File storage: connect your S3 bucket to Jodit Cloud
description: Give the Jodit Cloud editor a file browser and uploader backed by your own S3 bucket (AWS, MinIO, Cloudflare R2, Yandex). Setup in the cabinet, bucket policies, public and JWT authorization modes.
keywords: jodit cloud file browser, jodit cloud upload, jodit s3, jodit cloud storage, filebrowser api key, jodit uploader cloud
---

# File storage

Jodit Cloud can serve a file browser and an uploader for your editor without a backend on your side. You connect an S3 bucket to your API key in the cabinet, and from then on the editor loaded from `cloud.xdsoft.net` comes with `uploader` and `filebrowser` already configured. Files go straight into your bucket. We keep the credentials encrypted and use them per request; nothing is stored on our side.

The service behind it is the [Node.js connector](/jodit/examples/intergration/jodit-nodejs-aws-s3.html) with its S3 adapter, running at `https://cloud.xdsoft.net/files/`.

## What you need

New to AWS? [Set up an AWS S3 bucket](./file-storage-aws-setup.md) walks through the account, the bucket, the policies and the access key click by click.

- A bucket on Amazon S3 or any S3-compatible service (MinIO, Cloudflare R2, Yandex Object Storage, DigitalOcean Spaces, Backblaze B2).
- An access key that may list the bucket and read, write and delete objects under a prefix (folder) of your choice.
- The prefix readable from a browser: either a bucket policy that allows public reads on it, or a CDN in front of the bucket. The editor loads images by URL, the connector never proxies them.

### IAM policy

```json
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "s3:ListBucket",
			"Resource": "arn:aws:s3:::my-bucket",
			"Condition": {
				"StringLike": { "s3:prefix": ["uploads/*", "uploads"] }
			}
		},
		{
			"Effect": "Allow",
			"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
			"Resource": "arn:aws:s3:::my-bucket/uploads/*"
		}
	]
}
```

### Bucket policy for public reads

```json
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": "*",
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::my-bucket/uploads/*"
		}
	]
}
```

On AWS, "Block public access" has to allow bucket policies for this to take effect. If you would rather keep the bucket private, put CloudFront (or your provider's CDN) in front of it and use the CDN URL as the public URL below.

## Connect the bucket

1. Open your order in the [account dashboard](/jodit/pro/cab/), then the Cloud key, then the **Storage** tab.
2. Pick the provider. Amazon S3 needs a region; the other providers need their endpoint, and MinIO and R2 use path-style URLs (the tab sets this for you).
3. Enter the bucket, the prefix (for example `uploads`), the public URL of that prefix, and the access key pair.
4. Choose how visitors are authorized (next section) and save.
5. Press **Test connection**. The test lists the prefix, writes a small marker object and deletes it again, so it exercises exactly the three permissions the connector needs. A failure names the step that did not pass.

The loader is cached for five minutes, so a page loaded right after saving may still come without the file browser. Reload after that.

## Who may use the file browser

The API key is in your page source, so anybody who can open the page can send requests with it. The Storage tab offers two ways to decide what they may do.

### Public: one role for every visitor

Every request from a page on your [allowed domains](./settings.md#allowed-domains-referrers) gets the same role. The default is **Uploader**: browse, upload and edit images, but no renaming or deleting. Choose it when the page itself is behind your own login, or when uploads from visitors are what you want anyway.

Roles:

| Role | May |
| --- | --- |
| Viewer | browse and download |
| Uploader | Viewer plus upload files, resize and crop images |
| Editor | Uploader plus rename, move, copy and delete files |
| Admin | Editor plus create and remove folders |

### JWT: a token per user, signed by your backend

Your backend issues a short-lived token for the logged-in user, the page passes it to the editor, and the connector verifies it with a secret you set in the Storage tab. The `role` claim in the token picks one of the roles above; a token without a role is a viewer. Requests without a valid token are refused.

Generate the secret in the tab (or paste your own, at least 32 characters) and keep it in your backend configuration. It is not shown again after saving.

Issuing a token:

```javascript
// Node.js, npm install jsonwebtoken
const jwt = require('jsonwebtoken');

const token = jwt.sign({ role: 'editor', sub: user.id }, process.env.JODIT_FILES_SECRET, {
	algorithm: 'HS256',
	expiresIn: '1h'
});
```

```php
// PHP, composer require firebase/php-jwt
use Firebase\JWT\JWT;

$token = JWT::encode(
	['role' => 'editor', 'sub' => $user->id, 'exp' => time() + 3600],
	$_ENV['JODIT_FILES_SECRET'],
	'HS256'
);
```

```python
# Python, pip install pyjwt
import jwt, time

token = jwt.encode(
    {"role": "editor", "sub": user.id, "exp": int(time.time()) + 3600},
    JODIT_FILES_SECRET,
    algorithm="HS256",
)
```

Passing it to the editor:

```html
<script src="https://cloud.xdsoft.net/v4/jodit-pro/?key=YOUR_API_KEY"></script>
<script>
	const token = '...'; // rendered into the page by your backend

	JoditLoader.ready().then(() => {
		Jodit.make('#editor', {
			filebrowser: { ajax: { headers: { Authorization: 'Bearer ' + token } } },
			uploader: { headers: { Authorization: 'Bearer ' + token } }
		});
	});
</script>
```

The uploader and file browser URLs are already set by the loader; the options above only add the header. If a header is not an option in your setup, the token is also accepted as a `token` query parameter.

## What ends up in the bucket

- A file at `/photos/cat.jpg` in the file browser is the object `uploads/photos/cat.jpg`.
- Creating a folder writes a zero-byte object `uploads/photos/`, the same convention the AWS console uses.
- Thumbnails are stored next to the originals in a `_thumbs` folder.
- Objects uploaded by other tools appear in the file browser as long as they are under the prefix and their extension is allowed by the connector.

Traffic and storage are between your bucket and your users. We do not meter or limit them.

## Disconnecting

The Disconnect button in the Storage tab removes the credentials from our side and takes the uploader and file browser out of the loader. Nothing is deleted from the bucket.

## Troubleshooting

### The editor has no file browser

The key has no storage yet, or the loader was cached before you saved. Wait five minutes and reload.

### Test connection fails at the list step

The access key cannot `s3:ListBucket`, or the region or endpoint is wrong. AWS reports the right region in the error message.

### Test connection fails at the write step

`s3:PutObject` is missing on the prefix, or the bucket has Object Lock or a deny rule.

### Files upload but images do not show

The public URL is wrong or the prefix is not publicly readable. Open the public URL of an uploaded file in a browser: a 403 means the bucket policy or CDN is missing.

### 403 from cloud.xdsoft.net/files/

The page's domain is not in the key's allowed referrers, the key is blocked, or the role does not allow the action.

### 401 in JWT mode

No token, a token signed with another secret, or an expired one. Check that the secret in your backend is the one saved in the tab.
