Tokens¶
What is a Token?¶
Tokens protect access to your Tinybird resources.
Any operations to manage your Tinybird resources via the CLI or REST API require a valid Token with the necessary permissions. Access to the APIs you publish in Tinybird are also protected with Tokens.
Tokens can have different scopes. This means you can limit which operations a specific Token can do. You can create Tokens that are, for example, only able to do admin operations on Tinybird resources, or only have READ
permission for a specific Data Source.
Tinybird represents tokens using the icon.
What should I use Tokens for?¶
There are two types of Tokens.
- When performing operations on your account (like importing data, creating Data Sources, or publishing APIs via the CLI or REST API) you need a Token. For this purpose, use a Static Token.
- When publishing an API that exposes your data to an application, you need a Token to successfully interact with the API. For this purpose, use a JWT.
Monitor Token usage¶
You can monitor Token usage using Tinybird's Service Data Sources. See the guide "Monitor API Performance" for more.
Tokens¶
Tinybird Tokens, also known as "Static Tokens", are permanent and meant to be long-term. They are stored inside Tinybird and don't have an expiration date or time. They are useful for backend-to-backend integrations (where you call Tinybird as another service).
Token scopes¶
When a Token is created, you have the choice to give it a set of zero or more scopes that define which tables can be accessed by that Token, and which methods can be used to access them.
A READ
Token can be augmented with a SQL filter. This allows you to further restrict what data a Token grants access to. Using this, you can implement row-level security on a READ
-scoped Token.
Available scopes syntax
Value | Description |
---|---|
DATASOURCES:CREATE | Enables your Token to create and append data to Data Sources. |
DATASOURCES:APPEND:datasource_name | Allows your Token to append data to the defined Data Sources. |
DATASOURCES:DROP:datasource_name | Allows your Token to delete the specified Data Sources. |
DATASOURCES:READ:datasource_name | Gives your Token read permissions for the specified Data Sources. Also gives read for the quarantine Data Source. |
DATASOURCES:READ:datasource_name:sql_filter | Gives your Token read permissions for the specified table with the sql_filter applied. |
PIPES:CREATE | Allows your Token to create new Pipes and manipulate existing ones. |
PIPES:DROP:pipe_name | Allows your Token to delete the specified Pipe. |
PIPES:READ:pipe_name | Gives your Token read permissions for the specified Pipe. |
PIPES:READ:pipe_name:sql_filter | Gives your Token read permissions for the specified Pipe with the sql_filter applied. |
TOKENS | Gives your Token the capacity of managing Tokens. |
ADMIN | All permissions will be granted. You should not use this Token except in really specific cases. Use it carefully! |
When adding the DATASOURCES:READ
scope to a Token, it automatically gives read permissions to the quarantine Data Source associated with it.
Applying Tokens with filters to queries that use the FINAL clause is not supported. If you need to apply auth filters to deduplications, use an alternative strategy (see deduplication strategies).
Default Workspace Tokens¶
All Workspaces are created with a set of basic Tokens that you can add to by creating additional Tokens:
admin token
for that Workspace (for signing JWTs).admin <your-email> token
for that Workspace that belongs specifically to your user account (for using with Tinybird CLI).create datasource token
for creating Data Sources in that Workspace.user token
for creating new Workspaces or deleting ones where are an admin (see below).
Some Tokens are created automatically by Tinybird during certain operations like scheduled copies, and these Tokens can be updated.
Your User Token¶
Your User Token is specific to your user account. It's a permanent Token that enables you to perform operations that are not limited to a single Workspace, such as creating new Workspaces.
You can only obtain your User Token from your Workspace in the Tinybird UI > Tokens > user token
.
Create a Token¶
In the Tinybird UI, navigate to Tokens > Plus (+) icon. Descriptively rename the new Token and update its scopes using the table above as a guide.
JSON Web Tokens (JWTs)
BETA
¶JWTs are currently in public beta. They are not feature-complete and may change in the future. If you have any feedback or suggestions, contact Tinybird at [email protected] or in the Community Slack.
JWTs are signed tokens that allow you to securely authorize and share data between your application and Tinybird. If you want to read more about JWTs, check out the JWT.io website.
Importantly, JWTs are not stored in Tinybird. They are created by you, inside your application, and signed with a shared secret between your application and Tinybird. Tinybird validates the signature of the JWT, using the shared secret, to ensure it's authentic.
When to use JWTs¶
The primary purpose for JWTs is to allow your application to call Tinybird API Endpoints from the frontend without proxying via your backend.
If you are building an application where a frontend component needs data from a Tinybird API Endpoint, you can use JWTs to authorize the request directly from the frontend.
The typical pattern looks like this:
- A user starts a session in your application.
- The frontend requests a JWT from your backend.
- Your backend generates a new JWT, signed with the Tinybird shared secret, and returns to the frontend.
- The frontend uses the JWT to call the Tinybird API Endpoints directly.
JWT payload¶
The payload of a JWT is a JSON object that contains the following fields:
Key | Example Value | Required | Description |
---|---|---|---|
workspace_id | workspaces_id | Yes | The UUID of your Tinybird Workspace, found in the Workspace list (locate the Workspace name in the nav bar > use Copy ID button), the Settings section (the three dots), or by using tb workspace current from the CLI. |
name | frontend_jwt | Yes | Used to identify the token in the tinybird.pipe_stats_rt table, useful for analytics, does not need to be unique. |
exp | 123123123123 | Yes | The Unix timestamp (UTC) showing the expiry date & time. Once a token has expired, Tinybird returns a 403 HTTP status code. |
scopes | [{"type": "PIPES:READ", "resource": "requests_per_day", "fixed_params": {"org_id": "testing"}}] | Yes | Used to pass data to Tinybird, including the Tinybird scope, resources and fixed parameters. |
scopes.type | PIPES:READ | Yes | The type of scope, e.g., READ. See JWT scopes for supported scopes. |
scopes.resource | t_b9427fe2bcd543d1a8923d18c094e8c1 or top_airlines | Yes | The ID or name of the Pipe that the scope applies to, i.e., which API Endpoint the token can access. |
scopes.fixed_params | {"org_id": "testing"} | No | Pass arbitrary fixed values to the API Endpoint. These values can be accessed by Pipe templates to supply dynamic values at query time. |
limits | {"rps": 10} | No | You can limit the number of requests per second (rps) the JWT can perform. Learn more in the JWT rate limit section. |
Check out the JWT example below to see what a complete payload looks like.
JWT algorithm¶
Tinybird always uses HS256 as the algorithm for JWTs and does not read the alg
field in the JWT header. You can skip the alg
field in the header.
JWT scopes¶
Value | Description |
---|---|
PIPES:READ:pipe_name | Gives your Token read permissions for the specified Pipe |
JWT expiration¶
JWTs can have an expiration time that gives each Token a finite lifespan.
Setting the exp
field in the JWT payload is mandatory, and not setting it will result in a 403 HTTP status code from Tinybird when requesting the API Endpoint.
Tinybird validates that a JWT has not expired before allowing access to the API Endpoint.
If a Token has expired, Tinybird returns a 403 HTTP status code.
JWT fixed parameters¶
Fixed parameters allow you to pass arbitrary values to the API Endpoint. These values can be accessed by Pipe templates to supply dynamic values at query time.
For example, consider the following fixed parameter:
Example fixed parameters
{ "fixed_params": { "org_id": "testing" } }
This passes a parameter called org_id
with the value testing
to the API Endpoint. You can then use this value in your SQL queries:
Example SQL query
SELECT fieldA, fieldB FROM my_pipe WHERE org_id = '{{ String(org_id) }}'
This is particularly useful when you want to pass dynamic values to an API Endpoint that are set by your backend and must be safe from user tampering. A good example is multi-tenant applications that require row-level security, where you need to filter data based on a user or tenant ID.
The value org_id
will always be the one specified in the fixed_params
. Even if you specify a new value in the URL when requesting the endpoint, Tinybird will always use the one specified in the JWT.
You can use JWT fixed parameters in combination with Pipe dynamic parameters.
JWT example¶
For example, take the following payload with all required and optional fields:
Example payload
{ "workspace_id": "workspaces_id", "name": "frontend_jwt", "exp": 123123123123, "scopes": [ { "type": "PIPES:READ", "resource": "requests_per_day", "fixed_params": { "org_id": "testing" } } ], "limits": { "rps": 10 } }
Then use the Admin Token from your Workspace to sign the payload, for example:
Example Workspace Admin Token
p.eyJ1IjogIjA1ZDhiYmI0LTdlYjctNDAzZS05NGEyLWM0MzFhNDBkMWFjZSIsICJpZCI6ICI3NzUxMDUzMC0xZjE4LTRkNzMtOTNmNS0zM2MxM2NjMDUxNTUiLCAiaG9zdCI6ICJldV9zaGFyZWQifQ.Xzh4Qjz0FMRDXFuFIWPI-3DWEC6y-RFBfm_wE3_Qp2M
With the payload and Admin Token above, the signed JWT payload would look like this:
Example JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3Jrc3BhY2VfaWQiOiIzMTA0OGI3Ni01MmU4LTQ5N2ItOTBhNC0wYzZhNTUxMzkyMGQiLCJuYW1lIjoiZnJvbnRlbmRfand0IiwiZXhwIjoxMjMxMjMxMjMxMjMsInNjb3BlcyI6W3sidHlwZSI6IlBJUEVTOlJFQUQiLCJyZXNvdXJjZSI6ImVhNDdmZDlkLWJjNDgtNDIwZC1hNmY2LTk1NDgxZmJiM2Y3YyIsImZpeGVkX3BhcmFtcyI6eyJvcmdfaWQiOiJ0ZXN0aW5nIn19XSwiaWF0IjoxNzE3MDYzNzQwfQ.t-9BRLI6MrhOAuvt1mBSTBTU7TOdJFunBjr78TuqpVg
You can use the JWT.io debugger to verify the above example.
JWT limitations¶
- You cannot refresh JWTs individually from inside Tinybird as they are not stored in Tinybird. You must do this from your application, or you can globally invalidate all JWTs by refreshing your Admin Token.
- If you refresh your Admin Token, all the tokens will be invalidated.
- If your token is expired or invalidated, you'll get a 403 HTTP status code from Tinybird when requesting the API Endpoint.
Create a JWT¶
Create a JWT in production¶
There is wide support for creating JWTs in many programming languages and frameworks. Any library that supports JWTs should work with Tinybird.
A common library to use with Python is PyJWT. Common libraries for JavaScript are jsonwebtoken and jose.
Create a JWT in Python using pyjwt
import jwt import datetime import os TINYBIRD_SIGNING_KEY = os.getenv('TINYBIRD_SIGNING_KEY') def generate_jwt(): expiration_time = datetime.datetime.utcnow() + datetime.timedelta(hours=3) payload = { "workspace_id": "workspaces_id", "name": "frontend_jwt", "exp": expiration_time, "scopes": [ { "type": "PIPES:READ", "resource": "requests_per_day", "fixed_params": { "org_id": "testing" } } ] } return jwt.encode(payload, TINYBIRD_SIGNING_KEY, algorithm='HS256')
Create a JWT using the CLI or the API¶
If for any reason you don't want to generate a JWT on your own, Tinybird provides an API and a CLI utility to create JWTs.
Create a JWT with the Tinybird CLI
tb token create jwt my_jwt --ttl 1h --scope PIPES:READ --resource my_pipe --filters "column_name=value"
Error handling¶
There are many reasons why a request might return a 403
status code. When a 403
is received, check the following:
- Confirm the JWT is valid and has not expired (the expiration time is in the
exp
field in the JWT's payload). - The generated JWTs can only read Tinybird API Endpoints. Confirm you're not trying to use the JWT to access other APIs.
- Confirm the JWT has a scope to read the endpoint you are trying to read. Check the payload of the JWT at https://jwt.io/.
- If you generated the JWT outside of Tinybird (without using the API or the CLI), make sure you are using the Workspace
admin token
, not your personal one.
Rate limits for JWTs¶
Check the limits page for limits on ingestion, queries, API Endpoints, and more.
When you specify a limits.rps
field in the payload of the JWT, Tinybird will use the name specified in the payload of the JWT to track the number of requests being done. If the number of requests goes above the limit, Tinybird starts rejecting new requests and returns an "HTTP 429 Too Many Requests" error. Check the limits docs for more information.
The following example shows the tracking of all requests done by frontend_jwt
. Once you reach 10 requests per second, Tinybird would start rejecting requests:
Example payload with global rate limit
{ "workspace_id": "workspaces_id", "name": "frontend_jwt", "exp": 123123123123, "scopes": [ { "type": "PIPES:READ", "resource": "requests_per_day", "fixed_params": { "org_id": "testing" } } ], "limits": { "rps": 10 } }
If rps <= 0
, Tinybird ignores the limit and assumes there is no limit.
As the name
field does not have to be unique, all the tokens generated using the name=frontend_jwt
would be under the same umbrella. This can be very useful if you want to have a global limit in one of your apps or components.
If you want to just limit for each specific user, you could generate a JWT using the following payload. In this case, you would specify a unique name so the limits only apply to each user:
Example of a payload with isolated rate limit
{ "workspace_id": "workspaces_id", "name": "frontend_jwt_user_<unique identifier>", "exp": 123123123123, "scopes": [ { "type": "PIPES:READ", "resource": "requests_per_day", "fixed_params": { "org_id": "testing" } } ], "limits": { "rps": 10 } }
Next steps¶
- Follow a walkthrough guide: How to consume APIs in a Next.js frontend with JWTs.
- Read about the Tinybird Tokens API.
- Understand Branches in Tinybird.