πͺ Tokens¶
Meerschaum tokens are long-lived API keys that grant programmatic access to a Meerschaum instance. They are a secure way to authenticate for services like IoT devices or CI/CD pipelines without using your username and password.
Tokens are tied to a specific user and have a defined set of permissions, called scopes.
When you create a token, you receive three key pieces of information: a Client ID, a Client Secret, and an API Key.
Write it down!
The Client Secret is only shown once upon token creation, so be sure to copy it somewhere safe when registering tokens.
- Client ID: A public, unique identifier (
UUID) - Client Secret: A private secret (treat this like a password)
- API Key: To be used in the
Authorizationheader (contains Client ID and Secret within).
Additionally, tokens have the following attributes:
- Label: A human-readable name to help you identify the token
- Expiration: An optional timestamp after which the token will become invalid
Set the
expirationtoNoneto prevent a token from expiring (use at your own risk!) - Scopes: A list of permissions that define what actions the token can perform
- User: The user account that owns the token
β Registering¶
You can create new tokens via the action register token:
This will prompt you for the owner of the token and print the Client ID, Client Secret and API Key. Registering to an api instance will assign the token the connector's configured user.
π Web UI¶
The easiest way to can manage tokens is on the Web Console. Open the user menu (your username, at the top right) and choose Tokens. From here, you can:
- Create new tokens with New token.
- Edit, invalidate, or delete existing tokens from the context menu (
β ).
When you create a new token, a form prompts you for a label, expiration date, and scopes. The Grant all scopes, including custom and future ones switch (the scope *) is on by default for an administrator or a holder of * (for anyone else the form starts from your own scopes and the switch is off); turn it off to pick built-in scopes from a checklist and to type custom (plugin) scopes. The edit form of a token that holds * shows the switch on, and saving it keeps *. After registration, you must copy the generated credentials, as the secret will not be shown again.

π Python API¶
In addition to the CLI and Web UI, you can manage tokens directly on instance connectors.
Creating a Token¶
To create a token, instantiate a meerschaum.core.Token object and call its register() method.
Creating a new token
import meerschaum as mrsm
from meerschaum.core import Token, User
# Tokens must be associated with a user.
user = User('myuser', instance='sql:main')
# The token will be managed by the 'sql:main' instance connector.
token = Token(
label='my-iot-device',
user=user,
instance='sql:main',
)
# The register() method generates the credentials and saves the token.
success, msg = token.register()
if not success:
print(msg)
else:
print(f"Successfully registered token '{token.label}'")
print(f" Client ID: {token.id}")
print(f" Client Secret: {token.secret}")
print(f" API Key: {token.get_api_key()}")
Fetching Tokens¶
You can retrieve a list of all tokens for a user from an instance connector.
import meerschaum as mrsm
conn = mrsm.get_connector('sql:main')
user = mrsm.core.User('myuser', instance=conn)
# Admins can see all tokens, including those without a user.
# Regular users only see their own tokens.
tokens = conn.get_tokens(user=user)
for token in tokens:
print(token)
Editing a Token¶
You can modify a token's label, expiration date, and scopes.
from datetime import datetime, timedelta, timezone
# Get the first token from the list.
token = tokens[0]
# Extend the expiration by 30 days.
if token.expiration:
token.expiration += timedelta(days=30)
else:
token.expiration = datetime.now(timezone.utc) + timedelta(days=30)
# Limit the token's scopes.
token.scopes = ['read:pipes', 'write:pipes']
success, msg = token.edit()
Invalidating and Deleting Tokens¶
If a token is compromised, you can invalidate it immediately. Invalidated tokens cannot be used but remains registered; deleting a token removes it permanently.
# Invalidate the token.
success, msg = token.invalidate()
# Delete the token permanently.
success, msg = token.delete()
βοΈ Authorization¶
There are two ways to use a token to authenticate with the API:
- Post the Client ID and Client Secret to
/login. The standard OAuth flow now acceptsclient_idandclient_secret(in addition tousernameandpassword). This returns short-lived bearer tokens. - Set the API Key directly in the
Authorizationheader. For situations where the standard OAuth flow isn't feasible (e.g. some IoT workloads), you can directly embed the API Key in theAuthorizationheader. The API Key wraps the Client ID and Secret and is authenticated on every request.
Authenticating with curl
π― Scopes¶
A token (and a user, through the scopes attribute of their account) holds a list of scope strings, and every API route requires the scopes it names (pipes:read, jobs:execute, jobs:stop, ...). A request missing one is refused with 403 and Missing required scope: '<scope>'.
*grants all scopes, including custom and future scopes. It is stored literally and checked on every request, so a*token keeps working when a plugin defines a new scope or a later release adds one. Use it for trusted automation.edit tokensandedit userskeep a*you type as*(v4 replaced it with the list of built-in scopes), and so doregister tokens --scopes '*',POST /tokens/registerwith"scopes": ["*"]and the console's token form. When no scopes are given, a new token gets its owner's scopes (an explicitly empty list,scopes=[], stays empty), and a new user (register users) follows the instance's default role (see Teams, Access and Locks).- A token carries at most its owner's scopes. Registering or editing a token with a scope the owner does not hold, or with
*when the owner is neither an administrator nor a holder of*, is refused with403(or a failure inregister tokens/edit tokensand the console) naming each disallowed scope; nothing is trimmed. A token registered without scopes gets its owner's own, and editing a token keeps the scopes it already holds. The console's register form starts from your own scopes, and "Grant all scopes" is on by default only for an administrator or a holder of*. - Only the owner or an administrator may change a token. Editing, invalidating or deleting another user's token answers
403; only an administrator may make an invalidated token valid again; an edit that omitsscopesoris_validkeeps them.mrsm edit tokensand the other token actions work on the instance directly with the operator's own access and are trusted; the rule is enforced by anapi:instance's server. - Custom scopes are plain strings. A plugin's
@api_pluginroutes may require any scope, for exampleScopedAuth(['myplugin:read']), and a token is granted it by listing it explicitly (--scopes myplugin:read pipes:read). Meerschaum does not validate scope names, so a typo grants nothing. - Stopping a job needs
jobs:executeandjobs:stop. v4 required a misspelledjosb:stopthat no one could hold, so only*tokens and administrators could stop jobs over the API. v5 requiresjobs:stop, and still accepts a token that explicitly holds the legacyjosb:stopin its place. - Running actions. Remote actions need
actions:executeandjobs:execute; creating jobs also needsjobs:write. Settingapi.permissions.actions.non_admin: false(start api --secure) restricts these operations to administrators. Restricted keys follow the remote command limits even when their owner is an administrator. Pipe Sync and Verify controls use the Pipe's own permissions. See who may run actions.