Configuration

OAuth 2.0 / OpenID Connect Authentication

LavinMQ supports OAuth 2.0 and OpenID Connect authentication using JWT tokens. Clients connect by providing a JWT token as the password, and LavinMQ validates the token and extracts permissions from it.

Quick Start

Minimal configuration:

[main]
auth_backends = oauth

[oauth]
issuer = https://your-oauth-provider.example.com

This enables OAuth authentication and tells LavinMQ where to fetch public keys. By default, LavinMQ uses the sub and client_id claims for the username. To customize which claims are used, set preferred_username_claims.

Configuration

All OAuth settings go in the [oauth] section of /etc/lavinmq/lavinmq.ini.

Configuration Variables

Variable Description
issuer Required. Your OAuth provider's issuer URL. LavinMQ uses this to discover the JWKS endpoint and validate token issuers. The .well-known/openid-configuration endpoint must be accessible.

Example: issuer = https://oauth-provider.example.com
preferred_username_claims Comma-separated list of JWT claims to check for the username. LavinMQ tries each in order and uses the first non-empty value. The username is used for logging and display only—authorization is based on scopes.

Default: preferred_username_claims = sub,client_id

Example: preferred_username_claims = preferred_username,sub,email
resource_server_id Identifier for extracting nested roles and as fallback for audience validation. Use this when your tokens have roles in resource_access[resource_server_id].roles, or when you want automatic scope prefix filtering using {resource_server_id}.

Example: resource_server_id = lavinmq-service
additional_scopes_keys Custom JWT claim containing permissions. Use this if your OAuth provider stores permissions in a non-standard claim name.

Example: additional_scopes_keys = permissions
scope_prefix Prefix to filter scopes. Only scopes starting with this prefix are used, and the prefix is removed before parsing. Useful when tokens contain permissions for multiple services. If not set, uses {resource_server_id}. as prefix if resource_server_id is configured.

Example: scope_prefix = lavinmq:
verify_aud Enable/disable audience claim validation. Keep this true to ensure tokens are intended for LavinMQ. Set to false only if your OAuth provider doesn't include aud claims.

Default: verify_aud = true
audience Expected audience value. Required when verify_aud is true and tokens contain aud claims. Falls back to resource_server_id if not set.

Example: audience = lavinmq-api
jwks_cache_ttl How long (in seconds) to cache public keys. Lower values mean more frequent key fetches. Higher values reduce network traffic but delay key rotation detection. Your OAuth provider's Cache-Control header overrides this setting.

Default: jwks_cache_ttl = 3600

Authentication Backends

Configure multiple backends in the [main] section:

# OAuth only
auth_backends = oauth

# Try OAuth first, fallback to local
auth_backends = oauth,local

# Try local first, fallback to OAuth
auth_backends = local,oauth

Backends are tried in order until one succeeds.

Permissions

Scope Format

Permissions follow this format: {permission_type}:{vhost}/{pattern}

  • permission_type: configure, read, or write
  • vhost: URL-encoded virtual host name (%2f for the default / vhost, * for all)
  • pattern: Resource pattern (* is replaced with .* internally)

Examples:

configure:%2f/*          # Configure all resources in default vhost
read:%2f/*               # Read from default vhost
write:%2f/*              # Write to default vhost
configure:production/*   # Configure in production vhost
read:*/*                 # Read from all vhosts

Note: For MQTT connections, permission checks are not enforced by default. You must enable them explicitly:

[mqtt]
permission_check_enabled = true

Administrative Tags

Use tag:{tag_name} for administrative permissions:

tag:management

How Scopes Are Extracted

LavinMQ looks for permissions in these token claims (in order):

1. resource_access[resource_server_id].roles (if resource_server_id is configured)

{
  "resource_access": {
    "lavinmq-service": {
      "roles": ["configure:%2f/*", "read:%2f/*", "write:%2f/*"]
    }
  }
}

2. scope (standard OAuth claim, space-separated)

{
  "scope": "configure:%2f/*  read:%2f/*  write:%2f/*"
}

3. Custom claim (if additional_scopes_keys is configured)

{
  "permissions": ["configure:%2f/*", "read:%2f/*", "write:%2f/*"]
}

All sources are combined—users get the union of permissions from all claims.

Connecting Clients

Clients connect by providing the JWT token as the password:

  • Username: Any value (informational only)
  • Password: JWT token

The token must be valid, unexpired, and contain the required claims and scopes.

Token Lifecycle

Expiration

LavinMQ monitors token expiration. When a token expires, the connection is automatically closed and the client must reconnect with a new token.

Token Refresh

Clients can update their token without reconnecting using the AMQP update-secret frame.

How to refresh:

  1. Before the current token expires, get a new token from your OAuth provider
  2. Send update-secret frame with the new token
  3. LavinMQ validates the new token and updates permissions
  4. Connection continues with new token

Note: Token refresh is only supported for AMQP connections. MQTT clients must reconnect with a new token.

Public Keys

LavinMQ automatically fetches and caches public keys from your OAuth provider’s JWKS endpoint. Keys are refreshed in the background before they expire.

Requirements:

  • LavinMQ must be able to reach {issuer}/.well-known/openid-configuration
  • LavinMQ must be able to reach the JWKS endpoint (discovered from above)
  • OAuth provider must use HTTPS with valid certificates

Key rotation: When your OAuth provider rotates keys, LavinMQ automatically fetches the new keys on the next refresh cycle. Ensure your jwks_cache_ttl is shorter than your provider’s key rotation grace period.

Limitations

Token Support

  • RS256 only: Other algorithms are not supported
  • JWT format only: Opaque tokens and other formats are not supported
  • OIDC discovery required: OAuth provider must support .well-known/openid-configuration

Permissions

  • Permissions are extracted at authentication time
  • To update permissions, use token refresh or reconnect
  • All permissions must be in the JWT token

Token Refresh

  • AMQP only (MQTT clients must reconnect)
  • Username cannot change between tokens
  • Not all client libraries support update-secret

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.


Can’t find what you’re looking for? Let us know
Was this helpful?

Search