Authentication
Auth Keys
For multipart Assembly-creation requests authenticated with an Auth Key, include an auth object
inside the JSON-encoded params form field. The smallest such params value is shown below.
{
"auth": {
"key": "23c96d084c744219a2ce156772ec3211"
}
}
The key field refers to the Auth Key associated with your Transloadit Workspace, found
on the Credentials page. The above is the minimum authentication object for
an Assembly request that uses an Auth Key. Other endpoints and authentication methods can use
different request formats, as described by their endpoint documentation and below.
Assemblies that use /transloadit/import, directly or through a Template, require
either a bearer token or signed params with a future params.auth.expires timestamp.
This applies even when Workspace Signature Authentication is disabled. An Auth Key alone
is not sufficient; bearer-authenticated requests do not need a separate signature or expiry.
Signature Authentication
We recommend enabling Signature Authentication on your account, especially if you're integrating with Transloadit from an untrusted environment (such as from the browser with Uppy). You can enable Signature Authentication from your Workspace Settings.
We strongly recommend enabling Signature Authentication when interfacing with our API, particularly in untrusted environments where users may be able to access your Auth Key.
With Signature Authentication enabled, your Workspace's Auth Secret (found
next to your Auth Key on the Credentials page) is
then used as the key for an HMAC generated from the exact serialized params value. That value contains both a key (which is your
Auth Key as mentioned earlier), and an expires param, which is a timestamp in the near
future used as an expiry date for the request.
For creating Assemblies with Transloadit, your back-end could calculate a Signature that only covers certain parameters, authenticated users, and a timeframe that it deems legitimate usage. For instance, it would refuse to generate a signature for users that are not logged in. You could use any business logic on the server-side here to decide if you hand out a signature, or not. Transloadit can require a correct signature for the payload when an API request authenticates with your Auth Key.
To require Signature Authentication for API requests authenticated with your Auth Key:
- Go to the Workspace Settings in your account.
- In the API Settings section, enable the Require a correct Signature option.
- Hit the Save button.
Valid bearer tokens bypass signature requirements, including Workspace and Template settings; token scopes and audience restrictions still apply. These settings do not add authentication to capability-based access such as Assembly status, cancellation or resumable upload URLs. Keep Assembly IDs and capability URLs private, and follow each endpoint’s authentication guidance.
Most back-end SDKs automatically use Signature Authentication when you supply your Auth Secret. So perhaps, just this introduction is all you need to know. If you are integrating Transloadit into untrusted environments, however, such as browsers (Uppy!), you’ll want to continue reading to see how your back-end can supply signatures to it.
How to generate Signatures
So, how does this all look?
The typical params field when creating an Assembly without Signature Authentication
is as follows:
{
"auth": {
"key": "23c96d084c744219a2ce156772ec3211"
},
"steps": {
// …
}
}
The auth.key in this example is the Auth Key from
API Credentials in your account.
To sign this request, the additional auth.expires field needs to be added. This adds it to our
payload, which is protected by our signature. If someone would change it, Transloadit would reject
the request as the signature no longer matches. You signed a different payload than the one we
received. If the signature does match, then we will naturally compare and reject by date as
instructed. This way, requests become very hard to indefinitely repeat by a third party that got a
hold of this payload. Because even though our A+ grade HTTPS should already go a long way in
preventing that, browser cache could be easier to snoop on.
The expires property must contain a timestamp in the (near) future. Use ISO 8601 format
(YYYY-MM-DDTHH:mm:ss.sssZ) for the date, making sure that UTC is used for the timezone. For
example:
{
"auth": {
"key": "23c96d084c744219a2ce156772ec3211",
"expires": "YOUR_FUTURE_ISO_8601_TIMESTAMP"
},
"steps": {
// …
}
}
To calculate the signature for this request:
- From your front-end, stringify the above JavaScript object into JSON and send it to your back-end.
- From your back-end, calculate an RFC 6234-compliant HMAC
hex signature on the string, with your Auth Secret as the key and the algorithm
configured in your Auth Key’s
signature_algo. New Auth Keys default tosha384. Legacy Auth Keys without a configured algorithm acceptsha384,sha256, orsha1. Prefix thesignaturestring with the algorithm name in lowercase. For example, the default algorithm usessha384:<HMAC-signature>. You can send that string to your front-end (as long as you made the appropriate checks to guarantee it was a genuine request from your front-end). - From your front-end, add a
signaturemultipart POST field containing this value to your request (e.g., with a hidden field in an HTML form).
If your implementation uses a template_id instead of steps, there’s no need to
generate a signature for the Instructions that your Template contains. We
should only sign communication payloads.
We strongly recommend including a randomly generated params.nonce value for each request
at the top level of params. This makes independently generated signatures distinct and avoids accidental
signature reuse. A nonce does not make retries idempotent: retrying an Assembly-creation request
can create another Assembly. Handle retry deduplication in your application when needed.
Do not reuse signed params across endpoints. Template reads, Auth Key listing, Template Credential
listing, and billing reads reject signatures already recorded for a different endpoint or used
to create an Assembly, with SIGNATURE_REUSE_DETECTED. Generate fresh signed params for each request.
The full request should look similar to the below:
{
"params": {
"auth": {
"key": "23c96d084c744219a2ce156772ec3211",
"expires": "YOUR_FUTURE_ISO_8601_TIMESTAMP",
},
"nonce": "04ac6cb6-df43-41fb-a7fd-e5dd711a64e1",
"steps": {
// …
},
},
"signature": "sha384:YOUR_SIGNATURE",
}
Once the request was received by Transloadit, we also generate a signature following the same
process, and compare the two signatures. If the signatures are different, then our servers will
respond with INVALID_SIGNATURE.
In summary, the process is as follows:
- Generate a JSON payload to send to Transloadit as the
paramsfield. - Calculate a signature based off the contents of the payload, using your Auth Secret as a key.
- Send the request to Transloadit, with the signature passed in the
signaturefield - Transloadit will calculate the same signature using your account's Auth Secret, and the contents of the payload.
- If the signatures match, the request is permitted, and an appropriate response is sent.
Otherwise, the request is denied, and an error will be returned with the code
INVALID_SIGNATURE.
This lets Transloadit authenticate the caller and verify the integrity of params, since a third
party could not calculate a matching signature without access to your Auth Secret. TLS authenticates Transloadit to your client
and protects the connection. Webhook signing is a separate flow for requests Transloadit sends to
your servers.
Below are a few examples of how to perform a POST request to create an Assembly. We strongly recommend using one of our SDKs, which handle signature generation automatically and are well-tested.
Webhooks are signed differently from API requests.
Transloadit signs the exact JSON string in the transloadit form field using
HMAC-SHA1 and the applicable Auth Secret. The signature field contains
the hexadecimal digest without an algorithm prefix. Follow the
webhook verification instructions, including how to select the Auth Secret,
instead of using the API-request signing examples below.
Example code for different languages
The examples below demonstrate creating Assemblies using our official SDKs. The SDKs handle all signature generation internally, making integration simpler and more secure.
// yarn add @transloadit/node
// or
// npm install --save @transloadit/node
import { Transloadit } from '@transloadit/node'
const transloadit = new Transloadit({
authKey: 'YOUR_TRANSLOADIT_KEY',
authSecret: 'YOUR_TRANSLOADIT_SECRET',
})
const response = await transloadit.createAssembly({
params: {
template_id: 'YOUR_TRANSLOADIT_TEMPLATE_ID',
// your other params like notify_url, fields, etc.
},
waitForCompletion: true,
})
console.log(response)
If you need to calculate a signature separately (e.g., for front-end use), you can use
calcSignature:
const { signature, params } = transloadit.calcSignature({
template_id: 'YOUR_TRANSLOADIT_TEMPLATE_ID',
})
console.log(signature, params)
If you prefer to see the raw signature implementation details (e.g., to implement signing in a
language we don’t have an SDK for), check the source code links above. The signature is an
RFC 6234-compliant HMAC hex digest calculated on the
JSON-encoded params string, using your Auth Secret as
the key and the algorithm configured in your Auth Key’s signature_algo. New Auth Keys default
to sha384. Prefix the signature with its lowercase algorithm name
(e.g., sha384:...).
curl --fail-with-body -sS --location 'https://api2.transloadit.com/assemblies' \
--form 'params={"auth":{"key":"23c96d084c744219a2ce156772ec3211","expires":"YOUR_FUTURE_ISO_8601_TIMESTAMP"},"template_id":"9cf67cbba601e37ee10c442b037e0"}' \
--form 'signature=sha384:YOUR_SIGNATURE' \
--form 'files=@/path/to/your/file.jpg'
Smart CDN signed URLs
To sign a Smart CDN URL, a similar process as for regular API signatures is used. A HMAC digest is calculated on a string, that is derived from the Smart CDN URL, with the Auth Secret as the key. For the signature to be valid, the used Auth Key must be enabled for Smart CDN use.
To generate a signed Smart CDN URL, use the Auth Key designated for Smart CDN usage from your
Credentials page. Smart CDN URLs require sha256. Regular API request
signatures use the algorithm configured in the Auth Key’s signature_algo; new Auth Keys default
to sha384.
Legacy Smart CDN signatures based on s= and expires= are deprecated. New integrations should
always use sig= with exp=.
The generation of a Smart CDN signature must be performed on the back-end. The process uses the Auth Secret, which is confidential and must not be exposed to your users on the front-end.
A typical Smart CDN URL has the following structure:
https://[your-workspace].tlcdn.com/[template-name]/[file-path]?[parameters]
[your-workspace]is your Transloadit Workspace name[template-name]is the name of your Template[file-path]is the path to the file you want to transform[parameters]are desired transformation parameters (e.g.h=100)
A signed Smart CDN URL is generated by following these steps:
- Add the
expquery parameter for defining a time in the future after which the signature is not accepted by the Smart CDN anymore. This is useful to limit temporal access to a file. The expiration moment is represented by the number of milliseconds since the UNIX epoch (the midnight at the beginning of January 1, 1970, UTC). While this parameter is optional, we highly recommend always setting an expiration time. For example, a signature usingexp=1722517200000is valid until Thu, 01 Aug 2024 13:00:00 GMT. - Add the
auth_keyquery parameter to define the Auth Key corresponding to the Auth Secret that is used to create the signature. If this parameter is not set, Transloadit's API assumes that the oldest, Smart-CDN-enabled Auth Key pair has been used for the signature. Setting theauth_keyparameters allows you to rotate your Auth Key without interrupting your users, and we thus highly recommend setting it. For example:auth_key=23c96d084c744219a2ce156772ec3211 - Sort the query parameters by key in ascending order using UTF-16 code units, matching
URLSearchParams.sort(). The sorting should be stable, i.e. if a key appears multiple times in the query string, the corresponding values should retain their relative ordering. For example,h=100&f=png&f=jpg&auth_key=hello&exp=123is sorted intoauth_key=hello&exp=123&f=png&f=jpg&h=100. - Construct the string to sign by concatenating the values:
The values for
[your-workspace]/[template-name]/[file-path]?[sorted-parameters][your-workspace],[template-name], and[file-path]must be URL-encoded to ensure they only contain URL-safe characters. Note that the string does not start with a leading slash. The?character must be omitted if[sorted-parameters]is empty. - Calculate an RFC 6234-compliant HMAC hex signature on the
string to sign, with your Auth Secret as the key, and SHA256 as the hash algorithm.
Prefix the hex signature with the algorithm name in lowercase and a colon, i.e.
sha256:. For example, for SHA256, usesha256:[hmac-signature]. - Append the prefixed hex signature under the
sigquery parameter to the URL, giving the signed Smart CDN URL:The values forhttps://[your-workspace].tlcdn.com/[template-name]/[file-path]?[parameters]&sig=sha256:[hmac-signature][your-workspace],[template-name], and[file-path]must be URL-encoded to ensure they only contain URL-safe characters. This signed URL can then be sent to or used in your front-end until the expiration date is reached.
Security and cache lifetime
Signed Smart CDN URLs are not just an access-control mechanism. Their expiration also determines how long a freshly generated result may remain cacheable.
- Shorter
expvalues reduce the replay window and tighten access control. - Longer
expvalues increase cache reuse, reduce origin work, and generally lower latency and encoding volume. - In practice, the effective cache lifetime of a signed Smart CDN response is bounded by the remaining signature lifetime.
That means the trade-off is straightforward:
- More security sensitivity: use a shorter
exp, which also means a shorter effective cache TTL. - More cache reuse and lower cost: use a longer
exp, which also means the URL remains usable for longer.
Choose the expiration window according to the sensitivity of the content and how much cache reuse you want. For many image and preview use cases, a moderate expiration window gives a good balance. For highly sensitive content, use a much shorter one.
Example code
Below you can find examples in different languages for generating signed Smart CDN URLs using our SDKs.
// yarn add @transloadit/node
// or
// npm install --save @transloadit/node
import { Transloadit } from '@transloadit/node'
const transloadit = new Transloadit({
authKey: 'YOUR_TRANSLOADIT_KEY',
authSecret: 'YOUR_TRANSLOADIT_SECRET',
})
const url = transloadit.getSignedSmartCDNUrl({
workspace: 'YOUR_WORKSPACE',
template: 'YOUR_TEMPLATE',
input: 'image.png',
urlParams: { height: 100, width: 100 },
})
console.log(url)
Read access after cancellation
Canceled Workspaces cannot create new bearer tokens. Endpoints that explicitly permit access after cancellation link to this recipe. Use an existing active Auth Key and its Auth Secret; the key must still grant the scopes listed for the endpoint. This does not restore write access or make other endpoints available after cancellation.
In a trusted server-side Node.js project, install the SDK with yarn add @transloadit/node.
Set TRANSLOADIT_KEY and TRANSLOADIT_SECRET, then set TRANSLOADIT_URL to the complete HTTPS
URL shown on the endpoint page, replacing any path parameters with your resource values.
Keep both credentials, the signed URL and the response private. Never run this setup in browser code.
The SDK signs params with sha384, the default for new Auth Keys, and supplies the expiry.
The example adds a fresh nonce to avoid signature reuse. If your key uses another signature
algorithm, pass it as the second argument to calcSignature. Put any endpoint filters inside
the object passed as its first argument, alongside the nonce.
The SDK does not call /token for this recipe.
Save this as read-api.mjs and run node read-api.mjs:
import { randomUUID } from 'node:crypto'
import { Transloadit } from '@transloadit/node'
const { TRANSLOADIT_KEY, TRANSLOADIT_SECRET, TRANSLOADIT_URL } = process.env
if (!TRANSLOADIT_KEY || !TRANSLOADIT_SECRET || !TRANSLOADIT_URL) {
throw new Error('Set TRANSLOADIT_KEY, TRANSLOADIT_SECRET, and TRANSLOADIT_URL')
}
const transloadit = new Transloadit({
authKey: TRANSLOADIT_KEY,
authSecret: TRANSLOADIT_SECRET,
})
const { params, signature } = transloadit.calcSignature({ nonce: randomUUID() })
const url = new URL(TRANSLOADIT_URL)
url.searchParams.set('params', params)
url.searchParams.set('signature', signature)
const response = await fetch(url, { redirect: 'error' })
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`)
const result = await response.json()
if (result.error) throw new Error(result.error)
console.log(JSON.stringify(result, null, 2))
Bearer tokens (client credentials)
If you need a short-lived token for server-to-server or headless clients, you can exchange your
Auth Key and Auth Secret for a Bearer token. This mirrors an OAuth
2.0 client_credentials flow but is handled directly by the Transloadit API. For the full endpoint
reference, see the /token API docs.
Using the token
Pass the token as Authorization: Bearer <access_token> on API requests. When a request is
authenticated with a valid Bearer token, API2 treats
Signature Authentication as satisfied and
skips signature validation. Signature Authentication is enforced only for key/secret requests.
Scope and audience checks still apply. The mcp audience is accepted by the MCP server and
rejected by regular API2 endpoints. You can omit auth.key in params, but the params envelope
is still required for endpoints that expect it.
curl --fail-with-body -sS --request POST \
--url 'https://api2.transloadit.com/assemblies' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--form 'params={"template_id":"YOUR_TEMPLATE_ID"}'
MCP auto-auth for /ai/chat
If your /ai/chat steps call a Transloadit-hosted MCP server, API2 can mint and inject a short-lived
Bearer token automatically (auto-auth). This is opt-in per MCP server entry:
{
"mcp_servers": [
{
"type": "http",
"url": "https://api2.transloadit.com/mcp",
"auth": "transloadit"
}
]
}
Behavior:
- If
auth: "transloadit"is set and noAuthorizationheader is present, API2 mints a token and injectsAuthorization: Bearer <token>. - If
Authorizationis already provided inmcp_servers[].headers, it is left untouched. - Auto-auth only works over HTTPS for Transloadit-managed apex hosts and subdomains:
transloadit.com,*.transloadit.com,transloadit.dev,*.transloadit.dev,transloadit.website,*.transloadit.website,transloadit.work,*.transloadit.work. - The URL must use port
443and the exact/mcppath or a subpath below/mcp/. - The URL must not contain credentials, a query string, or a fragment.
- The Auth Key must grant at least one of these safe MCP scopes:
assemblies:write,assemblies:read,templates:read. - The minted token is narrowed to the intersection of those safe MCP scopes and the Auth Key’s scopes; it never gains a scope that the Auth Key does not grant.
FAQs
Does Transloadit include signatures with its requests?
Transloadit signs Webhook requests so your server can verify their authenticity. Webhook signing is separate from the HMAC that authenticates API requests sent to Transloadit.
Why can’t I use my Auth Secret as the Bearer token?
Except for the server-to-server token exchange described above, your Auth Secret must
never be transmitted to a client or included in API request parameters. POST /token sends it as
the HTTP Basic password over HTTPS and must be called only from your back-end. For signed requests,
the secret remains on your back-end and is used as the HMAC key. This prevents a malicious actor
from intercepting a signed request and spoofing requests to your account. Keep your Auth Secret safe by using
whichever secret management system you prefer. Examples are: Vault,
AWS Secrets Manager,
GCP Secret Manager, and
Kubernetes Secrets, but there are many
more that could be suitable depending on your back-end platform of choice.
You should ensure that Auth Secrets are never included as part of the front-end of your application, or exposed to users.
What order do the keys in the body need to be in?
The order you choose for the keys in the body can be arbitrary, however it’s important to note that whichever order you choose needs to be consistent with your signature generation. The hash generated depends on the contents of the JSON, and a different ordering will generate a different hash, meaning your request will be denied.