Authentication
LavinMQ supports multiple authentication backends that can be chained together.
Authentication Chain
auth_backends defines an ordered list of authentication backends. When a client connects, each backend is tried in order; the first backend to return a successful authentication wins. If empty, only local authentication is used.
| Config Key | Section | Default | Description |
|---|---|---|---|
auth_backends |
[main] |
[] (local) |
Ordered, comma-separated list of authentication backends |
[main]
auth_backends = local,oauth
Available backends:
| Backend | Description |
|---|---|
local |
Username/password stored in the definitions file |
oauth |
JWT/OAuth2 token validation |
Local Authentication
The default authentication method. Users and their password hashes are stored in the server’s definitions file.
Password Hashing
Supported hashing algorithms:
| Algorithm | Description |
|---|---|
| SHA256 | Default. Salted SHA-256 hash. |
| SHA512 | Salted SHA-512 hash |
| Bcrypt | Bcrypt with configurable cost |
| MD5 | Salted MD5 (legacy, not recommended) |
Default User
LavinMQ creates a default user on first start with the administrator tag.
| Config Key | Section | Default | Description |
|---|---|---|---|
default_user |
[main] |
guest |
Username of the default user |
default_password_hash |
[main] |
(hash of guest) |
Hashed password for the default user. Expects a hash value, not plaintext. |
default_user_only_loopback |
[main] |
true |
If true, the default user can only connect from loopback (127.0.0.1, ::1) |
OAuth2 / OIDC Authentication
JWT-based authentication using an external identity provider.
Configuration
[oauth]
issuer = https://auth.example.com
resource_server_id = lavinmq
preferred_username_claims = sub,client_id
verify_aud = true
audience = lavinmq
jwks_cache_ttl = 3600
| Option | Default | Description |
|---|---|---|
issuer |
(required) | OIDC issuer URL. Used to discover JWKS endpoint. |
client_id |
(none) | OAuth2 client ID. Required to enable management UI SSO (see below) |
mgmt_base_url |
(none) | Public base URL of the management UI. Enables SSO login when set together with issuer and client_id |
resource_server_id |
(none) | Resource server identifier |
preferred_username_claims |
sub,client_id |
JWT claims to extract the username from (tried in order) |
additional_scopes_keys |
[] |
Additional JWT claims to check for scope strings |
scope_prefix |
(none) | Prefix to strip from scope strings |
verify_aud |
true |
Verify the JWT aud claim |
audience |
(none) | Expected JWT audience value. Also sent as the audience parameter in the SSO authorization request |
jwks_cache_ttl |
3600 |
How long to cache the JWKS keys (seconds) |
Management UI SSO Login
When issuer, client_id, and mgmt_base_url are all set (and oauth is included in auth_backends), the management UI login page shows a “Sign in with SSO” button. Clicking it runs an OpenID Connect Authorization Code flow with PKCE against the issuer; on success the user is logged into the management UI with the returned token, which is validated the same way as tokens used for AMQP clients (see below).
mgmt_base_url is the public URL the browser uses to reach the management UI. It is used to build the OAuth redirect_uri (<mgmt_base_url>/oauth/callback), which must be registered as an allowed redirect URI on the OAuth client. For security it must use https://, or http:// with a localhost, 127.0.0.1, or [::1] host.
[main]
auth_backends = local,oauth
[oauth]
issuer = https://auth.example.com
client_id = lavinmq-mgmt
mgmt_base_url = https://lavinmq.example.com
audience = lavinmq
Because verify_aud defaults to true, SSO tokens must have an aud claim
matching either audience or resource_server_id. Alternatively set
verify_aud = false if audience validation is not wanted. When audience is
set it is also included in the authorization request, which some identity
providers (e.g. Auth0) require to issue a JWT access token instead of an
opaque one.
If any of the three keys is missing, the SSO button is hidden and only username/password login is available.
How It Works
- Client connects with a JWT token as the password
- The server validates the token signature against cached JWKS keys and verifies the audience (if
verify_audis enabled) - Username is extracted from the claims listed in
preferred_username_claims(tried in order; first non-empty value wins) - Tags and permissions are derived from the token’s scopes
- The token’s expiration time is tracked. Long-lived connections must refresh the token via
connection.update-secretbefore it expires.
Scope Sources
LavinMQ collects scopes from several places in the JWT, in this order:
resource_access.<resource_server_id>.roles— ifresource_server_idis configured (Keycloak-style claims).scope— the standard JWT scope claim, parsed as a space-separated list.- Additional claims listed in
additional_scopes_keys. Values can be strings (space-separated), arrays of strings, or nested objects keyed byresource_server_id.
Scope Filtering
Scopes are filtered by a prefix to isolate LavinMQ-specific entries from a larger token:
- If
scope_prefixis set, only scopes starting with that prefix are kept (prefix stripped). - If
scope_prefixis unset butresource_server_idis set, the prefix defaults to<resource_server_id>.. - If neither is set, all scopes are used as-is.
Scope Format
After filtering, each scope is interpreted as either a tag assignment or a permission grant.
Tag scopes:
tag:<tag-name>
Where <tag-name> is one of administrator, monitoring, management, policymaker, impersonator. Unknown tags are ignored. See Users and Permissions for what each tag grants.
Permission scopes:
<configure|read|write>:<vhost>/<resource-pattern>
Or with an optional routing-key segment (accepted for compatibility but ignored):
<configure|read|write>:<vhost>/<resource-pattern>/<routing-key>
<vhost>and<resource-pattern>are URL-decoded.<resource-pattern>supports*as a wildcard (translated to a regex). A bare*matches everything.- Multiple permission scopes for the same vhost and permission type are combined into a single regex (alternation).
- Permissions for vhosts not granted are denied by default (empty regex
^$).
Token scopes are the only source of permissions for OAuth users. Unlike local
users, an OAuth user who creates a vhost is not granted permissions on it;
access to the new vhost must be granted through the identity provider, e.g.
with wildcard vhost scopes such as read:*/*.
Examples
A token with these filtered scopes:
tag:management
read:%2F/.*
write:%2F/orders
configure:staging/temp.*
Grants the user the management tag, full read access on the / vhost, write access only to resources starting with orders on /, and configure access to resources matching temp* on the staging vhost.
Token Refresh
When the token expires, LavinMQ closes the connection unless the client sends connection.update-secret with a fresh token first. The username in the new token must match the original; tags and permissions are taken from the new token.
Ready to take the next steps?
Managed LavinMQ instance via CloudAMQP
LavinMQ has been built with performance and ease of use in mind - we've benchmarked a throughput of about 1,000,000 messages/sec . You can try LavinMQ without any installation hassle by creating a free instance on CloudAMQP. Signing up is a breeze.
Get started with CloudAMQP ->Help and feedback
We welcome your feedback and are eager to address any questions you may have about this piece or using LavinMQ. Join our Slack channel to connect with us directly. You can also find LavinMQ on GitHub.